From 51a7c4b5f2a0b2d0f6bc0c87ec2ee44b9697dc78 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Thu, 12 Dec 2019 14:51:59 +0100 Subject: [PATCH] TEST: Add test recipe and help program to test BIO_f_prefix() Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/10531) --- test/README | 5 +- test/bio_prefix_text.c | 267 ++++++++++++++++++ test/build.info | 5 + test/recipes/61-test_bio_prefix.t | 55 ++++ test/recipes/61-test_bio_prefix_data/args1.pl | 6 + test/recipes/61-test_bio_prefix_data/args2.pl | 3 + test/recipes/61-test_bio_prefix_data/in1.txt | 1 + test/recipes/61-test_bio_prefix_data/in2.txt | 1 + test/recipes/61-test_bio_prefix_data/out1.txt | 1 + test/recipes/61-test_bio_prefix_data/out2.txt | 1 + 10 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 test/bio_prefix_text.c create mode 100644 test/recipes/61-test_bio_prefix.t create mode 100644 test/recipes/61-test_bio_prefix_data/args1.pl create mode 100644 test/recipes/61-test_bio_prefix_data/args2.pl create mode 100644 test/recipes/61-test_bio_prefix_data/in1.txt create mode 100644 test/recipes/61-test_bio_prefix_data/in2.txt create mode 100644 test/recipes/61-test_bio_prefix_data/out1.txt create mode 100644 test/recipes/61-test_bio_prefix_data/out2.txt diff --git a/test/README b/test/README index 9a0938146e..17dffa0e7f 100644 --- a/test/README +++ b/test/README @@ -27,7 +27,10 @@ The number {nn} is (somewhat loosely) grouped as follows: 20-24 openssl commands (some otherwise not tested) 25-29 certificate forms, generation and verification 30-35 engine and evp -60-79 APIs +60-79 APIs: + 60 X509 subsystem + 61 BIO subsystem + 65 CMP subsystem 70 PACKET layer 80-89 "larger" protocols (CA, CMS, OCSP, SSL, TSA) 90-98 misc diff --git a/test/bio_prefix_text.c b/test/bio_prefix_text.c new file mode 100644 index 0000000000..4fc468a976 --- /dev/null +++ b/test/bio_prefix_text.c @@ -0,0 +1,267 @@ +/* + * Copyright 2019 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 + */ + +#include +#include +#include +#include +#include "opt.h" + +static BIO *bio_in = NULL; +static BIO *bio_out = NULL; +static BIO *bio_err = NULL; + +/*- + * This program sets up a chain of BIO_f_filter() on top of bio_out, how + * many is governed by the user through -n. It allows the user to set the + * indentation for each individual filter using -i and -p. Then it reads + * text from bio_in and prints it out through the BIO chain. + * + * The filter index is counted from the source/sink, i.e. index 0 is closest + * to it. + * + * Example: + * + * $ echo foo | ./bio_prefix_text -n 2 -i 1:32 -p 1:FOO -i 0:3 + * FOO foo + * ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * | | + * | +------ 32 spaces from filter 1 + * +-------------------------- 3 spaces from filter 0 + */ + +static size_t amount = 0; +static BIO **chain = NULL; + +typedef enum OPTION_choice { + OPT_ERR = -1, + OPT_EOF = 0, + OPT_AMOUNT, + OPT_INDENT, + OPT_PREFIX +} OPTION_CHOICE; + +static const OPTIONS options[] = { + { "n", OPT_AMOUNT, 'p', "Amount of BIO_f_prefix() filters" }, + /* + * idx is the index to the BIO_f_filter chain(), where 0 is closest + * to the source/sink BIO. If idx isn't given, 0 is assumed + */ + { "i", OPT_INDENT, 's', "Indentation in form '[idx:]indent'" }, + { "p", OPT_PREFIX, 's', "Prefix in form '[idx:]prefix'" }, + { NULL } +}; + +int opt_printf_stderr(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = BIO_vprintf(bio_err, fmt, ap); + va_end(ap); + return ret; +} + +static int run_pipe(void) +{ + char buf[4096]; + + while (!BIO_eof(bio_in)) { + size_t bytes_in; + size_t bytes_out; + + if (!BIO_read_ex(bio_in, buf, sizeof(buf), &bytes_in)) + return 0; + bytes_out = 0; + while (bytes_out < bytes_in) { + size_t bytes; + + if (!BIO_write_ex(chain[amount - 1], buf, bytes_in, &bytes)) + return 0; + bytes_out += bytes; + } + } + return 1; +} + +static int setup_bio_chain(const char *progname) +{ + BIO *next = NULL; + size_t n = amount; + + chain = OPENSSL_zalloc(sizeof(*chain) * n); + + if (chain != NULL) { + size_t i; + + next = bio_out; + BIO_up_ref(next); /* Protection against freeing */ + + for (i = 0; n > 0; i++, n--) { + BIO *curr = BIO_new(BIO_f_prefix()); + + if (curr == NULL) + goto err; + chain[i] = BIO_push(curr, next); + if (chain[i] == NULL) + goto err; + next = chain[i]; + } + } + return chain != NULL; + err: + /* Free the chain we built up */ + BIO_free_all(next); + OPENSSL_free(chain); + return 0; +} + +static void cleanup(void) +{ + if (chain != NULL) { + BIO_free_all(chain[amount - 1]); + OPENSSL_free(chain); + } + + BIO_free_all(bio_in); + BIO_free_all(bio_out); + BIO_free_all(bio_err); +} + +static int setup(void) +{ + OPTION_CHOICE o; + char *arg; + char *colon; + char *endptr; + size_t idx, indent; + const char *progname = opt_getprog(); + + bio_in = BIO_new_fp(stdin, BIO_NOCLOSE | BIO_FP_TEXT); + bio_out = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT); + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT); +#ifdef __VMS + bio_out = BIO_push(BIO_new(BIO_f_linebuffer()), bio_out); + bio_err = BIO_push(BIO_new(BIO_f_linebuffer()), bio_err); +#endif + + OPENSSL_assert(bio_in != NULL); + OPENSSL_assert(bio_out != NULL); + OPENSSL_assert(bio_err != NULL); + + + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_AMOUNT: + arg = opt_arg(); + amount = strtoul(arg, &endptr, 10); + if (endptr[0] != '\0') { + BIO_printf(bio_err, + "%s: -n argument isn't a decimal number: %s", + progname, arg); + return 0; + } + if (amount < 1) { + BIO_printf(bio_err, "%s: must set up at least one filter", + progname); + return 0; + } + if (!setup_bio_chain(progname)) { + BIO_printf(bio_err, "%s: failed setting up filter chain", + progname); + return 0; + } + break; + case OPT_INDENT: + if (chain == NULL) { + BIO_printf(bio_err, "%s: -i given before -n", progname); + return 0; + } + arg = opt_arg(); + colon = strchr(arg, ':'); + idx = 0; + if (colon != NULL) { + idx = strtoul(arg, &endptr, 10); + if (endptr[0] != ':') { + BIO_printf(bio_err, + "%s: -i index isn't a decimal number: %s", + progname, arg); + return 0; + } + colon++; + } else { + colon = arg; + } + indent = strtoul(colon, &endptr, 10); + if (endptr[0] != '\0') { + BIO_printf(bio_err, + "%s: -i value isn't a decimal number: %s", + progname, arg); + return 0; + } + if (idx >= amount) { + BIO_printf(bio_err, "%s: index (%zu) not within range 0..%zu", + progname, idx, amount - 1); + return 0; + } + if (!BIO_set_indent(chain[idx], (long)indent)) { + BIO_printf(bio_err, "%s: failed setting indentation: %s", + progname, arg); + return 0; + } + break; + case OPT_PREFIX: + if (chain == NULL) { + BIO_printf(bio_err, "%s: -p given before -n", progname); + return 0; + } + arg = opt_arg(); + colon = strchr(arg, ':'); + idx = 0; + if (colon != NULL) { + idx = strtoul(arg, &endptr, 10); + if (endptr[0] != ':') { + BIO_printf(bio_err, + "%s: -p index isn't a decimal number: %s", + progname, arg); + return 0; + } + colon++; + } else { + colon = arg; + } + if (idx >= amount) { + BIO_printf(bio_err, "%s: index (%zu) not within range 0..%zu", + progname, idx, amount - 1); + return 0; + } + if (!BIO_set_prefix(chain[idx], colon)) { + BIO_printf(bio_err, "%s: failed setting prefix: %s", + progname, arg); + return 0; + } + break; + default: + case OPT_ERR: + return 0; + } + } + return 1; +} + +int main(int argc, char **argv) +{ + int rv = EXIT_SUCCESS; + + opt_init(argc, argv, options); + rv = (setup() && run_pipe()) ? EXIT_SUCCESS : EXIT_FAILURE; + cleanup(); + return rv; +} diff --git a/test/build.info b/test/build.info index fc7007ed93..2b429d304c 100644 --- a/test/build.info +++ b/test/build.info @@ -706,6 +706,11 @@ IF[{- !$disabled{tests} -}] SOURCE[namemap_internal_test]=namemap_internal_test.c INCLUDE[namemap_internal_test]=.. ../include ../apps/include DEPEND[namemap_internal_test]=../libcrypto.a libtestutil.a + + PROGRAMS{noinst}=bio_prefix_text + SOURCE[bio_prefix_text]=bio_prefix_text.c $LIBAPPSSRC + INCLUDE[bio_prefix_text]=.. ../include ../apps/include + DEPEND[bio_prefix_text]=../libcrypto ENDIF SOURCE[ssl_ctx_test]=ssl_ctx_test.c diff --git a/test/recipes/61-test_bio_prefix.t b/test/recipes/61-test_bio_prefix.t new file mode 100644 index 0000000000..c77bdbfa32 --- /dev/null +++ b/test/recipes/61-test_bio_prefix.t @@ -0,0 +1,55 @@ +#! /usr/bin/env perl +# Copyright 2017-2018 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 strict; +use warnings; + +use OpenSSL::Test qw(:DEFAULT data_file); +use File::Compare qw(compare_text); + +setup('test_bio_prefix'); + +my %input_result = ( + 'in1.txt' => [ 'args1.pl', 'out1.txt' ], + 'in2.txt' => [ 'args2.pl', 'out2.txt' ], +); + +plan tests => 2 * scalar(keys %input_result); + +foreach (sort keys %input_result) { + SKIP: { + my $input_path = data_file($_); + my $args_path = data_file($input_result{$_}->[0]); + my $expected_path = data_file($input_result{$_}->[1]); + my $result_path = "test_bio_prefix-$_-stdout"; + my @args = do $args_path; + + skip "Problem prefixing $_", 1 + unless ok(run(test([ 'bio_prefix_text', @args ], + stdin => $input_path, stdout => $result_path)), + "prefixing $_ with args " . join(' ', @args)); + is(compare_text($result_path, $expected_path, \&cmp_line), 0, + "comparing the dump of $_ with $expected_path"); + } +} + +sub cmp_line { + return 0 if scalar @_ == 0; + + if (scalar @_ != 2) { + diag "Lines to compare less than 2: ", scalar @_; + return -1; + } + + $_[0] =~ s|\R$||; + $_[1] =~ s|\R$||; + my $r = $_[0] cmp $_[1]; + + diag "Lines differ:\n<: $_[0]\n>: $_[1]\n" unless $r == 0; + return $r; +} diff --git a/test/recipes/61-test_bio_prefix_data/args1.pl b/test/recipes/61-test_bio_prefix_data/args1.pl new file mode 100644 index 0000000000..e7038dc50d --- /dev/null +++ b/test/recipes/61-test_bio_prefix_data/args1.pl @@ -0,0 +1,6 @@ +( + -n => 2, + -i => '1:32', + -p => '1:FOO', + -i => '0:3' +); diff --git a/test/recipes/61-test_bio_prefix_data/args2.pl b/test/recipes/61-test_bio_prefix_data/args2.pl new file mode 100644 index 0000000000..2fe2b7bb63 --- /dev/null +++ b/test/recipes/61-test_bio_prefix_data/args2.pl @@ -0,0 +1,3 @@ +( + -n => 1, +); diff --git a/test/recipes/61-test_bio_prefix_data/in1.txt b/test/recipes/61-test_bio_prefix_data/in1.txt new file mode 100644 index 0000000000..257cc5642c --- /dev/null +++ b/test/recipes/61-test_bio_prefix_data/in1.txt @@ -0,0 +1 @@ +foo diff --git a/test/recipes/61-test_bio_prefix_data/in2.txt b/test/recipes/61-test_bio_prefix_data/in2.txt new file mode 100644 index 0000000000..5716ca5987 --- /dev/null +++ b/test/recipes/61-test_bio_prefix_data/in2.txt @@ -0,0 +1 @@ +bar diff --git a/test/recipes/61-test_bio_prefix_data/out1.txt b/test/recipes/61-test_bio_prefix_data/out1.txt new file mode 100644 index 0000000000..484e514ba4 --- /dev/null +++ b/test/recipes/61-test_bio_prefix_data/out1.txt @@ -0,0 +1 @@ + FOO foo diff --git a/test/recipes/61-test_bio_prefix_data/out2.txt b/test/recipes/61-test_bio_prefix_data/out2.txt new file mode 100644 index 0000000000..5716ca5987 --- /dev/null +++ b/test/recipes/61-test_bio_prefix_data/out2.txt @@ -0,0 +1 @@ +bar -- 2.34.1