mirror of
https://github.com/openssl/openssl.git
synced 2026-01-18 17:11:31 +01:00
Add ASN1_BIT_STRING_get_length()
From tb@openbsd.org with tests adapted by beck for OpenSSL. Fixes: https://github.com/openssl/openssl/issues/29184 Reviewed-by: Saša Nedvědický <sashan@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Neil Horman <nhorman@openssl.org> (Merged from https://github.com/openssl/openssl/pull/29387)
This commit is contained in:
committed by
Neil Horman
parent
d78e642f28
commit
da8f09846b
@@ -220,3 +220,36 @@ int ASN1_BIT_STRING_check(const ASN1_BIT_STRING *a,
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
int ASN1_BIT_STRING_get_length(const ASN1_BIT_STRING *abs, size_t *out_length,
|
||||
int *out_unused_bits)
|
||||
{
|
||||
size_t length;
|
||||
int unused_bits;
|
||||
|
||||
if (abs == NULL || abs->type != V_ASN1_BIT_STRING)
|
||||
return 0;
|
||||
|
||||
if (out_length == NULL || out_unused_bits == NULL)
|
||||
return 0;
|
||||
|
||||
length = abs->length;
|
||||
unused_bits = 0;
|
||||
|
||||
if ((abs->flags & ASN1_STRING_FLAG_BITS_LEFT) != 0)
|
||||
unused_bits = abs->flags & 0x07;
|
||||
|
||||
if (length == 0 && unused_bits != 0)
|
||||
return 0;
|
||||
|
||||
if (unused_bits != 0) {
|
||||
unsigned char mask = (1 << unused_bits) - 1;
|
||||
if ((abs->data[length - 1] & mask) != 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_length = length;
|
||||
*out_unused_bits = unused_bits;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -479,6 +479,10 @@ DEPEND[html/man3/ADMISSIONS.html]=man3/ADMISSIONS.pod
|
||||
GENERATE[html/man3/ADMISSIONS.html]=man3/ADMISSIONS.pod
|
||||
DEPEND[man/man3/ADMISSIONS.3]=man3/ADMISSIONS.pod
|
||||
GENERATE[man/man3/ADMISSIONS.3]=man3/ADMISSIONS.pod
|
||||
DEPEND[html/man3/ASN1_BIT_STRING_get_length.html]=man3/ASN1_BIT_STRING_get_length.pod
|
||||
GENERATE[html/man3/ASN1_BIT_STRING_get_length.html]=man3/ASN1_BIT_STRING_get_length.pod
|
||||
DEPEND[man/man3/ASN1_BIT_STRING_get_length.3]=man3/ASN1_BIT_STRING_get_length.pod
|
||||
GENERATE[man/man3/ASN1_BIT_STRING_get_length.3]=man3/ASN1_BIT_STRING_get_length.pod
|
||||
DEPEND[html/man3/ASN1_EXTERN_FUNCS.html]=man3/ASN1_EXTERN_FUNCS.pod
|
||||
GENERATE[html/man3/ASN1_EXTERN_FUNCS.html]=man3/ASN1_EXTERN_FUNCS.pod
|
||||
DEPEND[man/man3/ASN1_EXTERN_FUNCS.3]=man3/ASN1_EXTERN_FUNCS.pod
|
||||
@@ -3165,6 +3169,7 @@ DEPEND[man/man3/s2i_ASN1_IA5STRING.3]=man3/s2i_ASN1_IA5STRING.pod
|
||||
GENERATE[man/man3/s2i_ASN1_IA5STRING.3]=man3/s2i_ASN1_IA5STRING.pod
|
||||
IMAGEDOCS[man3]=
|
||||
HTMLDOCS[man3]=html/man3/ADMISSIONS.html \
|
||||
html/man3/ASN1_BIT_STRING_get_length.html \
|
||||
html/man3/ASN1_EXTERN_FUNCS.html \
|
||||
html/man3/ASN1_INTEGER_get_int64.html \
|
||||
html/man3/ASN1_INTEGER_new.html \
|
||||
@@ -3837,6 +3842,7 @@ html/man3/i2d_re_X509_tbs.html \
|
||||
html/man3/o2i_SCT_LIST.html \
|
||||
html/man3/s2i_ASN1_IA5STRING.html
|
||||
MANDOCS[man3]=man/man3/ADMISSIONS.3 \
|
||||
man/man3/ASN1_BIT_STRING_get_length.3 \
|
||||
man/man3/ASN1_EXTERN_FUNCS.3 \
|
||||
man/man3/ASN1_INTEGER_get_int64.3 \
|
||||
man/man3/ASN1_INTEGER_new.3 \
|
||||
|
||||
35
doc/man3/ASN1_BIT_STRING_get_length.pod
Normal file
35
doc/man3/ASN1_BIT_STRING_get_length.pod
Normal file
@@ -0,0 +1,35 @@
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
ASN1_BIT_STRING_get_length - ASN1_BIT_STRING accessors
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
int ASN1_BIT_STRING_get_length(const ASN1_BIT_STRING *bitstr, size_t *length, int *unused_bits);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
ASN1_BIT_STRING_get_length() returns the number of octets in I<bitstr>
|
||||
containing bit values in I<length> and the number of unused bits in
|
||||
the last octet in I<unused_bits>. The value returned in
|
||||
I<unused_bits> is guaranteed to be between 0 and 7, inclusive.
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
ASN1_BIT_STRING_get_length() returns 1 on success or 0 if the encoding
|
||||
of I<bitstr> is internally inconsistent, or if one of I<bitstr>,
|
||||
I<length>, or I<unused_bits> is NULL.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
this file except in compliance with the License. You can obtain a copy
|
||||
in the file LICENSE in the source distribution or at
|
||||
L<https://www.openssl.org/source/license.html>.
|
||||
|
||||
=cut
|
||||
@@ -586,6 +586,8 @@ int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs,
|
||||
int ASN1_BIT_STRING_num_asc(const char *name, BIT_STRING_BITNAME *tbl);
|
||||
int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, const char *name, int value,
|
||||
BIT_STRING_BITNAME *tbl);
|
||||
int ASN1_BIT_STRING_get_length(const ASN1_BIT_STRING *abs, size_t *length,
|
||||
int *unused_bits);
|
||||
|
||||
/* clang-format off */
|
||||
{-
|
||||
|
||||
268
test/asn1_string_test.c
Normal file
268
test/asn1_string_test.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/* ASN1_STRING tests */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
#include "testutil.h"
|
||||
|
||||
struct abs_get_length_test {
|
||||
const char *descr;
|
||||
int valid;
|
||||
const unsigned char der[20];
|
||||
int der_len;
|
||||
size_t length;
|
||||
int unused_bits;
|
||||
};
|
||||
|
||||
static const struct abs_get_length_test abs_get_length_tests[] = {
|
||||
{
|
||||
.descr = "zero bits",
|
||||
.valid = 1,
|
||||
.der = {
|
||||
0x03,
|
||||
0x01,
|
||||
0x00,
|
||||
},
|
||||
.der_len = 3,
|
||||
.length = 0,
|
||||
.unused_bits = 0,
|
||||
},
|
||||
{
|
||||
.descr = "zero bits one unused",
|
||||
.valid = 0,
|
||||
.der = {
|
||||
0x03,
|
||||
0x01,
|
||||
0x01,
|
||||
},
|
||||
.der_len = 3,
|
||||
},
|
||||
{
|
||||
.descr = "single zero bit",
|
||||
.valid = 1,
|
||||
.der = {
|
||||
0x03,
|
||||
0x02,
|
||||
0x07,
|
||||
0x00,
|
||||
},
|
||||
.der_len = 4,
|
||||
.length = 1,
|
||||
.unused_bits = 7,
|
||||
},
|
||||
{
|
||||
.descr = "single one bit",
|
||||
.valid = 1,
|
||||
.der = {
|
||||
0x03,
|
||||
0x02,
|
||||
0x07,
|
||||
0x80,
|
||||
},
|
||||
.der_len = 4,
|
||||
.length = 1,
|
||||
.unused_bits = 7,
|
||||
},
|
||||
{
|
||||
/* XXX - the library pretends this is 03 02 07 80 */
|
||||
.descr = "invalid: single one bit, seventh bit set",
|
||||
.valid = 1,
|
||||
.der = {
|
||||
0x03,
|
||||
0x02,
|
||||
0x07,
|
||||
0xc0,
|
||||
},
|
||||
.der_len = 4,
|
||||
.length = 1,
|
||||
.unused_bits = 7,
|
||||
},
|
||||
{
|
||||
.descr = "x.690, primitive encoding in example 8.6.4.2",
|
||||
.valid = 1,
|
||||
.der = {
|
||||
0x03,
|
||||
0x07,
|
||||
0x04,
|
||||
0x0A,
|
||||
0x3b,
|
||||
0x5F,
|
||||
0x29,
|
||||
0x1c,
|
||||
0xd0,
|
||||
},
|
||||
.der_len = 9,
|
||||
.length = 6,
|
||||
.unused_bits = 4,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* XXX - the library thinks it "decodes" this but gets it
|
||||
* quite wrong. Looks like it uses the unused bits of the
|
||||
* first component, and the unused bits octet 04 of the
|
||||
* second component somehow becomes part of the value.
|
||||
*/
|
||||
.descr = "x.690, constructed encoding in example 8.6.4.2",
|
||||
.valid = 1,
|
||||
.der = {
|
||||
0x23,
|
||||
0x80,
|
||||
0x03,
|
||||
0x03,
|
||||
0x00,
|
||||
0x0A,
|
||||
0x3b,
|
||||
0x03,
|
||||
0x05,
|
||||
0x04,
|
||||
0x5F,
|
||||
0x29,
|
||||
0x1c,
|
||||
0xd0,
|
||||
0x00,
|
||||
0x00,
|
||||
},
|
||||
.der_len = 16,
|
||||
.length = 7, /* XXX - should be 6. */
|
||||
.unused_bits = 0, /* XXX - should be 4. */
|
||||
},
|
||||
{
|
||||
.descr = "RFC 3779, 2.1.1, IPv4 address 10.5.0.4",
|
||||
.valid = 1,
|
||||
.der = {
|
||||
0x03,
|
||||
0x05,
|
||||
0x00,
|
||||
0x0a,
|
||||
0x05,
|
||||
0x00,
|
||||
0x04,
|
||||
},
|
||||
.der_len = 7,
|
||||
.length = 4,
|
||||
.unused_bits = 0,
|
||||
},
|
||||
{
|
||||
.descr = "RFC 3779, 2.1.1, IPv4 prefix 10.5.0/23",
|
||||
.valid = 1,
|
||||
.der = {
|
||||
0x03,
|
||||
0x04,
|
||||
0x01,
|
||||
0x0a,
|
||||
0x05,
|
||||
0x00,
|
||||
},
|
||||
.der_len = 6,
|
||||
.length = 3,
|
||||
.unused_bits = 1,
|
||||
},
|
||||
{
|
||||
.descr = "RFC 3779, 2.1.1, IPv6 address 2001:0:200:3::1",
|
||||
.valid = 1,
|
||||
.der = {
|
||||
0x03,
|
||||
0x11,
|
||||
0x00,
|
||||
0x20,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x03,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
},
|
||||
.der_len = 19,
|
||||
.length = 16,
|
||||
.unused_bits = 0,
|
||||
},
|
||||
{
|
||||
.descr = "RFC 3779, 2.1.1, IPv6 prefix 2001:0:200/39",
|
||||
.valid = 1,
|
||||
.der = {
|
||||
0x03,
|
||||
0x06,
|
||||
0x01,
|
||||
0x20,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
0x02,
|
||||
},
|
||||
.der_len = 8,
|
||||
.length = 5,
|
||||
.unused_bits = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
abs_get_length_test(const struct abs_get_length_test *tbl, int idx)
|
||||
{
|
||||
const struct abs_get_length_test *test = &tbl[idx];
|
||||
ASN1_BIT_STRING *abs = NULL;
|
||||
const unsigned char *p;
|
||||
int unused_bits, ret;
|
||||
size_t length;
|
||||
int success = 0;
|
||||
|
||||
p = test->der;
|
||||
if (!TEST_ptr(abs = d2i_ASN1_BIT_STRING(NULL, &p, test->der_len))) {
|
||||
TEST_info("%s, (idx=%d) - d2i_ASN1_BIT_STRING faled", __func__, idx);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = ASN1_BIT_STRING_get_length(abs, &length, &unused_bits);
|
||||
if (!TEST_int_eq(test->valid, ret)) {
|
||||
TEST_info("%s (idx=%d): %s ASN1_BIT_STRING_get_length want %d, got %d\n",
|
||||
__func__, idx, test->descr, test->valid, ret);
|
||||
goto err;
|
||||
}
|
||||
if (!test->valid)
|
||||
goto done;
|
||||
|
||||
if (!TEST_size_t_eq(length, test->length)
|
||||
|| !TEST_int_eq(unused_bits, test->unused_bits)) {
|
||||
TEST_info("%s: (idx=%d) %s: want (%zu, %d), got (%zu, %d)\n", __func__,
|
||||
idx, test->descr, test->length, test->unused_bits, length,
|
||||
unused_bits);
|
||||
goto err;
|
||||
}
|
||||
|
||||
done:
|
||||
success = 1;
|
||||
|
||||
err:
|
||||
ASN1_STRING_free(abs);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static int
|
||||
asn1_bit_string_get_length_test(int idx)
|
||||
{
|
||||
return abs_get_length_test(abs_get_length_tests, idx);
|
||||
}
|
||||
|
||||
int setup_tests(void)
|
||||
{
|
||||
ADD_ALL_TESTS(asn1_bit_string_get_length_test, OSSL_NELEM(abs_get_length_tests));
|
||||
return 1;
|
||||
}
|
||||
@@ -1096,6 +1096,11 @@ IF[{- !$disabled{tests} -}]
|
||||
INCLUDE[asn1_time_test]=../include ../apps/include
|
||||
DEPEND[asn1_time_test]=../libcrypto libtestutil.a
|
||||
|
||||
PROGRAMS{noinst}=asn1_string_test
|
||||
SOURCE[asn1_string_test]=asn1_string_test.c
|
||||
INCLUDE[asn1_string_test]=../include ../apps/include
|
||||
DEPEND[asn1_string_test]=../libcrypto libtestutil.a
|
||||
|
||||
# We disable this test completely in a shared build because it deliberately
|
||||
# redefines some internal libssl symbols. This doesn't work in a non-shared
|
||||
# build
|
||||
|
||||
12
test/recipes/90-test_asn1_string.t
Normal file
12
test/recipes/90-test_asn1_string.t
Normal file
@@ -0,0 +1,12 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
|
||||
use OpenSSL::Test::Simple;
|
||||
|
||||
simple_test("test_asn1_string", "asn1_string_test");
|
||||
@@ -2614,6 +2614,7 @@ ASN1_BIT_STRING_set ? 4_0_0 EXIST::FUNCTION:
|
||||
ASN1_BIT_STRING_set_bit ? 4_0_0 EXIST::FUNCTION:
|
||||
ASN1_BIT_STRING_get_bit ? 4_0_0 EXIST::FUNCTION:
|
||||
ASN1_BIT_STRING_check ? 4_0_0 EXIST::FUNCTION:
|
||||
ASN1_BIT_STRING_get_length ? 4_0_0 EXIST::FUNCTION:
|
||||
ASN1_BIT_STRING_name_print ? 4_0_0 EXIST::FUNCTION:
|
||||
ASN1_BIT_STRING_num_asc ? 4_0_0 EXIST::FUNCTION:
|
||||
ASN1_BIT_STRING_set_asc ? 4_0_0 EXIST::FUNCTION:
|
||||
|
||||
Reference in New Issue
Block a user