Coverage Report

Created: 2025-06-13 06:55

/src/openssl/crypto/der_writer.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
#include <stdlib.h>
11
#include <string.h>
12
#include "internal/cryptlib.h"
13
#include "internal/der.h"
14
#include "crypto/bn.h"
15
16
static int int_start_context(WPACKET *pkt, int tag)
17
0
{
18
0
    if (tag < 0)
19
0
        return 1;
20
0
    if (!ossl_assert(tag <= 30))
21
0
        return 0;
22
0
    return WPACKET_start_sub_packet(pkt);
23
0
}
24
25
static int int_end_context(WPACKET *pkt, int tag)
26
0
{
27
    /*
28
     * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this
29
     * sub-packet and this sub-packet has nothing written to it, the DER length
30
     * will not be written, and the total written size will be unchanged before
31
     * and after WPACKET_close().  We use size1 and size2 to determine if
32
     * anything was written, and only write our tag if it has.
33
     *
34
     */
35
0
    size_t size1, size2;
36
37
0
    if (tag < 0)
38
0
        return 1;
39
0
    if (!ossl_assert(tag <= 30))
40
0
        return 0;
41
42
    /* Context specific are normally (?) constructed */
43
0
    tag |= DER_F_CONSTRUCTED | DER_C_CONTEXT;
44
45
0
    return WPACKET_get_total_written(pkt, &size1)
46
0
        && WPACKET_close(pkt)
47
0
        && WPACKET_get_total_written(pkt, &size2)
48
0
        && (size1 == size2 || WPACKET_put_bytes_u8(pkt, tag));
49
0
}
50
51
int ossl_DER_w_precompiled(WPACKET *pkt, int tag,
52
                           const unsigned char *precompiled,
53
                           size_t precompiled_n)
54
0
{
55
0
    return int_start_context(pkt, tag)
56
0
        && WPACKET_memcpy(pkt, precompiled, precompiled_n)
57
0
        && int_end_context(pkt, tag);
58
0
}
59
60
int ossl_DER_w_boolean(WPACKET *pkt, int tag, int b)
61
0
{
62
0
    return int_start_context(pkt, tag)
63
0
        && WPACKET_start_sub_packet(pkt)
64
0
        && (!b || WPACKET_put_bytes_u8(pkt, 0xFF))
65
0
        && !WPACKET_close(pkt)
66
0
        && !WPACKET_put_bytes_u8(pkt, DER_P_BOOLEAN)
67
0
        && int_end_context(pkt, tag);
68
0
}
69
70
int ossl_DER_w_octet_string(WPACKET *pkt, int tag,
71
                            const unsigned char *data, size_t data_n)
72
0
{
73
0
    return int_start_context(pkt, tag)
74
0
        && WPACKET_start_sub_packet(pkt)
75
0
        && WPACKET_memcpy(pkt, data, data_n)
76
0
        && WPACKET_close(pkt)
77
0
        && WPACKET_put_bytes_u8(pkt, DER_P_OCTET_STRING)
78
0
        && int_end_context(pkt, tag);
79
0
}
80
81
int ossl_DER_w_octet_string_uint32(WPACKET *pkt, int tag, uint32_t value)
82
0
{
83
0
    unsigned char tmp[4] = { 0, 0, 0, 0 };
84
0
    unsigned char *pbuf = tmp + (sizeof(tmp) - 1);
85
86
0
    while (value > 0) {
87
0
        *pbuf-- = (value & 0xFF);
88
0
        value >>= 8;
89
0
    }
90
0
    return ossl_DER_w_octet_string(pkt, tag, tmp, sizeof(tmp));
91
0
}
92
93
static int int_der_w_integer(WPACKET *pkt, int tag,
94
                             int (*put_bytes)(WPACKET *pkt, const void *v,
95
                                              unsigned int *top_byte),
96
                             const void *v)
97
0
{
98
0
    unsigned int top_byte = 0;
99
100
0
    return int_start_context(pkt, tag)
101
0
        && WPACKET_start_sub_packet(pkt)
102
0
        && put_bytes(pkt, v, &top_byte)
103
0
        && ((top_byte & 0x80) == 0 || WPACKET_put_bytes_u8(pkt, 0))
104
0
        && WPACKET_close(pkt)
105
0
        && WPACKET_put_bytes_u8(pkt, DER_P_INTEGER)
106
0
        && int_end_context(pkt, tag);
107
0
}
108
109
static int int_put_bytes_uint32(WPACKET *pkt, const void *v,
110
                               unsigned int *top_byte)
111
0
{
112
0
    const uint32_t *value = v;
113
0
    uint32_t tmp = *value;
114
0
    size_t n = 0;
115
116
0
    while (tmp != 0) {
117
0
        n++;
118
0
        *top_byte = (tmp & 0xFF);
119
0
        tmp >>= 8;
120
0
    }
121
0
    if (n == 0)
122
0
        n = 1;
123
124
0
    return WPACKET_put_bytes__(pkt, *value, n);
125
0
}
126
127
/* For integers, we only support unsigned values for now */
128
int ossl_DER_w_uint32(WPACKET *pkt, int tag, uint32_t v)
129
0
{
130
0
    return int_der_w_integer(pkt, tag, int_put_bytes_uint32, &v);
131
0
}
132
133
static int int_put_bytes_bn(WPACKET *pkt, const void *v,
134
                            unsigned int *top_byte)
135
0
{
136
0
    unsigned char *p = NULL;
137
0
    size_t n = BN_num_bytes(v);
138
139
    /* The BIGNUM limbs are in LE order */
140
0
    *top_byte =
141
0
        ((bn_get_words(v) [(n - 1) / BN_BYTES]) >> (8 * ((n - 1) % BN_BYTES)))
142
0
        & 0xFF;
143
144
0
    if (!WPACKET_allocate_bytes(pkt, n, &p))
145
0
        return 0;
146
0
    if (p != NULL)
147
0
        BN_bn2bin(v, p);
148
0
    return 1;
149
0
}
150
151
int ossl_DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v)
152
0
{
153
0
    if (v == NULL || BN_is_negative(v))
154
0
        return 0;
155
0
    if (BN_is_zero(v))
156
0
        return ossl_DER_w_uint32(pkt, tag, 0);
157
158
0
    return int_der_w_integer(pkt, tag, int_put_bytes_bn, v);
159
0
}
160
161
int ossl_DER_w_null(WPACKET *pkt, int tag)
162
0
{
163
0
    return int_start_context(pkt, tag)
164
0
        && WPACKET_start_sub_packet(pkt)
165
0
        && WPACKET_close(pkt)
166
0
        && WPACKET_put_bytes_u8(pkt, DER_P_NULL)
167
0
        && int_end_context(pkt, tag);
168
0
}
169
170
/* Constructed things need a start and an end */
171
int ossl_DER_w_begin_sequence(WPACKET *pkt, int tag)
172
0
{
173
0
    return int_start_context(pkt, tag)
174
0
        && WPACKET_start_sub_packet(pkt);
175
0
}
176
177
int ossl_DER_w_end_sequence(WPACKET *pkt, int tag)
178
0
{
179
    /*
180
     * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this
181
     * sub-packet and this sub-packet has nothing written to it, the DER length
182
     * will not be written, and the total written size will be unchanged before
183
     * and after WPACKET_close().  We use size1 and size2 to determine if
184
     * anything was written, and only write our tag if it has.
185
     *
186
     * Because we know that int_end_context() needs to do the same check,
187
     * we reproduce this flag if the written length was unchanged, or we will
188
     * have an erroneous context tag.
189
     */
190
0
    size_t size1, size2;
191
192
0
    return WPACKET_get_total_written(pkt, &size1)
193
0
        && WPACKET_close(pkt)
194
0
        && WPACKET_get_total_written(pkt, &size2)
195
0
        && (size1 == size2
196
0
            ? WPACKET_set_flags(pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH)
197
0
            : WPACKET_put_bytes_u8(pkt, DER_F_CONSTRUCTED | DER_P_SEQUENCE))
198
0
        && int_end_context(pkt, tag);
199
0
}