/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 | } |