summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authortb <>2026-02-08 10:27:00 +0000
committertb <>2026-02-08 10:27:00 +0000
commit50933fb9bc6bf2281489d17ee48416a43163d847 (patch)
tree6d9729c1d5a62279e3a121d619a85668811430c0 /src/lib
parent36d1f52b62304ee4c3c58e4d9e76e912f868d8cc (diff)
downloadopenbsd-50933fb9bc6bf2281489d17ee48416a43163d847.tar.gz
openbsd-50933fb9bc6bf2281489d17ee48416a43163d847.tar.bz2
openbsd-50933fb9bc6bf2281489d17ee48416a43163d847.zip
Make truncation in ASN1_BIT_STRING_set_bit() explicit
Instead of relying on i2c_ASN1_BIT_STRING() to determine the "unused" bits on encoding, set them explicitly in abs->flags via a call to asn1_abs_set_unused_bits(). This means ASN1_STRING_FLAGS_BITS_LEFT is now set on a bit string, which was previously explicitly cleared. This also means that the encoding of a non-zero ASN1_BIT_STRING populated by setting the bits individually will now go through the if (a->flags & ASN1_STRING_FLAG_BITS_LEFT) path in i2c_ASN1_BIT_STRING(). The most prominent usage of this function is in X.509 for the keyUsage extension or the CRL reason codes. There's also the NS cert type, TS PKIFailureInfo and general BITLIST config strings. The reason for the truncation logic comes from the DER for NamedBitLists X.690, 11.2.2 below: X.680, 22.7: When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove) arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should therefore ensure that different semantics are not associated with such values which differ only in the number of trailing 0 bits. X.690, 11.2.2 Where ITU-T Rec. X.680 | ISO/IEC 8824-1, 22.7, applies, the bitstring shall have all trailing 0 bits removed before it is encoded. Note 1 - In the case where a size constraint has been applied, the abstract value delivered by a decoder to the application will be one of those satisfying the size constraint and differing from the transmitted value only in the number of trailing zero bits. Note 2 - If a bitstring value has no 1 bits, then an encoder shall encode the value with a length of 1 and an initial octet set to 0. ok kenjiro (on an earlier version) jsing
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/libcrypto/asn1/a_bitstr.c52
1 files changed, 43 insertions, 9 deletions
diff --git a/src/lib/libcrypto/asn1/a_bitstr.c b/src/lib/libcrypto/asn1/a_bitstr.c
index e656c43f0c..d84ecb025e 100644
--- a/src/lib/libcrypto/asn1/a_bitstr.c
+++ b/src/lib/libcrypto/asn1/a_bitstr.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: a_bitstr.c,v 1.48 2026/01/04 09:54:23 tb Exp $ */ 1/* $OpenBSD: a_bitstr.c,v 1.49 2026/02/08 10:27:00 tb Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -108,6 +108,39 @@ asn1_abs_set_unused_bits(ASN1_BIT_STRING *abs, uint8_t unused_bits)
108 return 1; 108 return 1;
109} 109}
110 110
111/*
112 * X.690, 11.2.2: [When a "NamedBitList" is used] [...], the bitstring shall
113 * have all trailing 0 bits removed before it is encoded.
114 */
115static int
116asn1_abs_trim_trailing_zero_bits(ASN1_BIT_STRING *abs)
117{
118 int unused_bits = 0;
119
120 /* Remove trailing zero octets. */
121 while (abs->length > 0 && abs->data[abs->length - 1] == 0)
122 abs->length--;
123
124 /* Remove trailing zero bits by setting the unused bits octet. */
125 if (abs->length > 0) {
126 uint8_t u8 = abs->data[abs->length - 1];
127
128 /* u8 != 0. Only keep least significant bit. */
129 u8 &= 0x100 - u8;
130
131 /* Count trailing zero bits. */
132 unused_bits = 7;
133 if ((u8 & 0x0f) != 0)
134 unused_bits -= 4;
135 if ((u8 & 0x33) != 0)
136 unused_bits -= 2;
137 if ((u8 & 0x55) != 0)
138 unused_bits -= 1;
139 }
140
141 return asn1_abs_set_unused_bits(abs, unused_bits);
142}
143
111int 144int
112ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len) 145ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len)
113{ 146{
@@ -133,12 +166,14 @@ ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value)
133 if (value == 0) 166 if (value == 0)
134 v = 0; 167 v = 0;
135 168
136 asn1_abs_clear_unused_bits(a);
137
138 if (a->length < w + 1 || a->data == NULL) { 169 if (a->length < w + 1 || a->data == NULL) {
139 /* Don't expand if there's no bit to set. */ 170 /*
171 * Don't expand if there's no bit to set.
172 * XXX - switch back to return 1 here when we drop
173 * ASN1_STRING_FLAG_BITS_LEFT?
174 */
140 if (value == 0) 175 if (value == 0)
141 return 1; 176 return asn1_abs_trim_trailing_zero_bits(a);
142 if ((c = recallocarray(a->data, a->length, w + 1, 1)) == NULL) { 177 if ((c = recallocarray(a->data, a->length, w + 1, 1)) == NULL) {
143 ASN1error(ERR_R_MALLOC_FAILURE); 178 ASN1error(ERR_R_MALLOC_FAILURE);
144 return 0; 179 return 0;
@@ -147,11 +182,9 @@ ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value)
147 a->length = w + 1; 182 a->length = w + 1;
148 } 183 }
149 184
150 a->data[w] = ((a->data[w]) & iv) | v; 185 a->data[w] = (a->data[w] & iv) | v;
151 while (a->length > 0 && a->data[a->length - 1] == 0)
152 a->length--;
153 186
154 return 1; 187 return asn1_abs_trim_trailing_zero_bits(a);
155} 188}
156LCRYPTO_ALIAS(ASN1_BIT_STRING_set_bit); 189LCRYPTO_ALIAS(ASN1_BIT_STRING_set_bit);
157 190
@@ -189,6 +222,7 @@ i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp)
189 if (a->flags & ASN1_STRING_FLAG_BITS_LEFT) { 222 if (a->flags & ASN1_STRING_FLAG_BITS_LEFT) {
190 bits = (int)a->flags & 0x07; 223 bits = (int)a->flags & 0x07;
191 } else { 224 } else {
225 /* XXX - dedup with asn1_abs_trim_trailing_zero_bits? */
192 j = 0; 226 j = 0;
193 for (; len > 0; len--) { 227 for (; len > 0; len--) {
194 if (a->data[len - 1]) 228 if (a->data[len - 1])