* Protocol - expected negotiated protocol. One of
SSLv3, TLSv1, TLSv1.1, TLSv1.2.
+* ClientVerifyCallback - the client's custom certificate verify callback.
+ Used to test callback behaviour. One of
+ - AcceptAll - accepts all certificates.
+ - RejectAll - rejects all certificates.
+
## Configuring the client and server
The client and server configurations can be any valid `SSL_CTX`
#include <string.h>
#include <openssl/bio.h>
+#include <openssl/x509_vfy.h>
#include <openssl/ssl.h>
#include "handshake_helper.h"
}
}
+static int verify_reject_callback(X509_STORE_CTX *ctx, void *arg) {
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION);
+ return 0;
+}
+
+static int verify_accept_callback(X509_STORE_CTX *ctx, void *arg) {
+ return 1;
+}
+
+/*
+ * Configure callbacks and other properties that can't be set directly
+ * in the server/client CONF.
+ */
+static void configure_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx,
+ const SSL_TEST_CTX *test_ctx)
+{
+ switch (test_ctx->client_verify_callback) {
+ case SSL_TEST_VERIFY_ACCEPT_ALL:
+ SSL_CTX_set_cert_verify_callback(client_ctx, &verify_accept_callback,
+ NULL);
+ break;
+ case SSL_TEST_VERIFY_REJECT_ALL:
+ SSL_CTX_set_cert_verify_callback(client_ctx, &verify_reject_callback,
+ NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+
typedef enum {
PEER_SUCCESS,
PEER_RETRY,
return INTERNAL_ERROR;
}
-HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx)
+HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx,
+ const SSL_TEST_CTX *test_ctx)
{
SSL *server, *client;
BIO *client_to_server, *server_to_client;
peer_status_t client_status = PEER_RETRY, server_status = PEER_RETRY;
handshake_status_t status = HANDSHAKE_RETRY;
+ configure_handshake(server_ctx, client_ctx, test_ctx);
+
server = SSL_new(server_ctx);
client = SSL_new(client_ctx);
OPENSSL_assert(server != NULL && client != NULL);
} HANDSHAKE_RESULT;
/* Do a handshake and report some information about the result. */
-HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx);
+HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx,
+ const SSL_TEST_CTX *test_ctx);
#endif /* HEADER_HANDSHAKE_HELPER_H */
$ENV{TEST_CERTS_DIR} = srctop_dir("test", "certs");
-my @conf_srcs = glob(srctop_file("test", "ssl-tests", "*.conf"));
-my @conf_files = map {basename($_)} @conf_srcs;
+my @conf_srcs = glob(srctop_file("test", "ssl-tests", "*.conf.in"));
+my @conf_files = map { basename($_) } @conf_srcs;
+map { s/\.in// } @conf_files;
# 02-protocol-version.conf test results depend on the configuration of enabled
# protocols. We only verify generated sources in the default configuration.
# We hard-code the number of tests to double-check that the globbing above
# finds all files as expected.
-plan tests => 2; # = scalar @conf_files
+plan tests => 3; # = scalar @conf_srcs
sub test_conf {
plan tests => 3;
plan tests =>
1 # For testss
+ 14 # For the first testssl
- + 16 # For the first testsslproxy
- + 16 # For the second testsslproxy
;
subtest 'test_ss' => sub {
note('test_ssl -- key U');
testssl("keyU.ss", $Ucert, $CAcert);
-note('test_ssl -- key P1');
-testsslproxy("keyP1.ss", "certP1.ss", "intP1.ss", "AB");
-
-note('test_ssl -- key P2');
-testsslproxy("keyP2.ss", "certP2.ss", "intP2.ss", "BC");
-
-
# -----------
# subtest functions
sub testss {
}
};
}
-
-sub testsslproxy {
- my $key = shift || srctop_file("apps","server.pem");
- my $cert = shift || srctop_file("apps","server.pem");
- my $CAtmp = shift;
- my @CA = $CAtmp ? ("-CAfile", $CAtmp) : ("-CApath", bldtop_dir("certs"));
- my @extra = @_;
-
- my @ssltest = ("ssltest_old",
- "-s_key", $key, "-s_cert", $cert,
- "-c_key", $key, "-c_cert", $cert);
-
- # plan tests => 16;
-
- note('Testing a lot of proxy conditions.');
-
- # We happen to know that certP1.ss has policy letters "AB" and
- # certP2.ss has policy letters "BC". However, because certP2.ss
- # has certP1.ss as issuer, when it's used, both their policy
- # letters get combined into just "B".
- # The policy letter(s) then get filtered with the given auth letter
- # in the table below, and the result gets tested with the given
- # condition. For details, read ssltest_old.c
- #
- # certfilename => [ [ auth, cond, expected result ] ... ]
- my %expected = ( "certP1.ss" => [ [ [ 'A', 'A' ], 1 ],
- [ [ 'A', 'B' ], 0 ],
- [ [ 'A', 'C' ], 0 ],
- [ [ 'A', 'A|B&!C' ], 1 ],
- [ [ 'B', 'A' ], 0 ],
- [ [ 'B', 'B' ], 1 ],
- [ [ 'B', 'C' ], 0 ],
- [ [ 'B', 'A|B&!C' ], 1 ],
- [ [ 'C', 'A' ], 0 ],
- [ [ 'C', 'B' ], 0 ],
- [ [ 'C', 'C' ], 0 ],
- [ [ 'C', 'A|B&!C' ], 0 ],
- [ [ 'BC', 'A' ], 0 ],
- [ [ 'BC', 'B' ], 1 ],
- [ [ 'BC', 'C' ], 0 ],
- [ [ 'BC', 'A|B&!C' ], 1 ] ],
- "certP2.ss" => [ [ [ 'A', 'A' ], 0 ],
- [ [ 'A', 'B' ], 0 ],
- [ [ 'A', 'C' ], 0 ],
- [ [ 'A', 'A|B&!C' ], 0 ],
- [ [ 'B', 'A' ], 0 ],
- [ [ 'B', 'B' ], 1 ],
- [ [ 'B', 'C' ], 0 ],
- [ [ 'B', 'A|B&!C' ], 1 ],
- [ [ 'C', 'A' ], 0 ],
- [ [ 'C', 'B' ], 0 ],
- [ [ 'C', 'C' ], 0 ],
- [ [ 'C', 'A|B&!C' ], 0 ],
- [ [ 'BC', 'A' ], 0 ],
- [ [ 'BC', 'B' ], 1 ],
- [ [ 'BC', 'C' ], 0 ],
- [ [ 'BC', 'A|B&!C' ], 1 ] ] );
-
- SKIP: {
- skip "Neither SSLv3 nor any TLS version are supported by this OpenSSL build", scalar(@{$expected{$cert}})
- if $no_anytls;
-
- foreach (@{$expected{$cert}}) {
- my $auth = $_->[0]->[0];
- my $cond = $_->[0]->[1];
- my $res = $_->[1];
- is(run(test([@ssltest, "-server_auth", @CA,
- "-proxy", "-proxy_auth", $auth,
- "-proxy_cond", $cond])), $res,
- "test tlsv1, server auth, proxy auth $auth and cond $cond (expect "
- .($res ? "success" : "failure").")");
- }
- }
-}
--- /dev/null
+# Generated with generate_ssl_tests.pl
+
+num_tests = 9
+
+test-0 = 0-verify-success
+test-1 = 1-verify-custom-reject
+test-2 = 2-verify-custom-allow
+test-3 = 3-noverify-success
+test-4 = 4-noverify-ignore-custom-reject
+test-5 = 5-noverify-accept-custom-allow
+test-6 = 6-verify-fail-no-root
+test-7 = 7-verify-custom-success-no-root
+test-8 = 8-verify-custom-fail-no-root
+# ===========================================================
+
+[0-verify-success]
+ssl_conf = 0-verify-success-ssl
+
+[0-verify-success-ssl]
+server = 0-verify-success-server
+client = 0-verify-success-client
+
+[0-verify-success-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+
+[0-verify-success-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+
+[test-0]
+ExpectedResult = Success
+
+
+# ===========================================================
+
+[1-verify-custom-reject]
+ssl_conf = 1-verify-custom-reject-ssl
+
+[1-verify-custom-reject-ssl]
+server = 1-verify-custom-reject-server
+client = 1-verify-custom-reject-client
+
+[1-verify-custom-reject-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+
+[1-verify-custom-reject-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+
+[test-1]
+ClientAlert = HandshakeFailure
+ClientVerifyCallback = RejectAll
+ExpectedResult = ClientFail
+
+
+# ===========================================================
+
+[2-verify-custom-allow]
+ssl_conf = 2-verify-custom-allow-ssl
+
+[2-verify-custom-allow-ssl]
+server = 2-verify-custom-allow-server
+client = 2-verify-custom-allow-client
+
+[2-verify-custom-allow-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+
+[2-verify-custom-allow-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+
+[test-2]
+ClientVerifyCallback = AcceptAll
+ExpectedResult = Success
+
+
+# ===========================================================
+
+[3-noverify-success]
+ssl_conf = 3-noverify-success-ssl
+
+[3-noverify-success-ssl]
+server = 3-noverify-success-server
+client = 3-noverify-success-client
+
+[3-noverify-success-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+
+[3-noverify-success-client]
+CipherString = DEFAULT
+
+
+[test-3]
+ExpectedResult = Success
+
+
+# ===========================================================
+
+[4-noverify-ignore-custom-reject]
+ssl_conf = 4-noverify-ignore-custom-reject-ssl
+
+[4-noverify-ignore-custom-reject-ssl]
+server = 4-noverify-ignore-custom-reject-server
+client = 4-noverify-ignore-custom-reject-client
+
+[4-noverify-ignore-custom-reject-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+
+[4-noverify-ignore-custom-reject-client]
+CipherString = DEFAULT
+
+
+[test-4]
+ClientVerifyCallback = RejectAll
+ExpectedResult = Success
+
+
+# ===========================================================
+
+[5-noverify-accept-custom-allow]
+ssl_conf = 5-noverify-accept-custom-allow-ssl
+
+[5-noverify-accept-custom-allow-ssl]
+server = 5-noverify-accept-custom-allow-server
+client = 5-noverify-accept-custom-allow-client
+
+[5-noverify-accept-custom-allow-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+
+[5-noverify-accept-custom-allow-client]
+CipherString = DEFAULT
+
+
+[test-5]
+ClientVerifyCallback = AcceptAll
+ExpectedResult = Success
+
+
+# ===========================================================
+
+[6-verify-fail-no-root]
+ssl_conf = 6-verify-fail-no-root-ssl
+
+[6-verify-fail-no-root-ssl]
+server = 6-verify-fail-no-root-server
+client = 6-verify-fail-no-root-client
+
+[6-verify-fail-no-root-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+
+[6-verify-fail-no-root-client]
+CipherString = DEFAULT
+VerifyMode = Peer
+
+
+[test-6]
+ClientAlert = UnknownCA
+ExpectedResult = ClientFail
+
+
+# ===========================================================
+
+[7-verify-custom-success-no-root]
+ssl_conf = 7-verify-custom-success-no-root-ssl
+
+[7-verify-custom-success-no-root-ssl]
+server = 7-verify-custom-success-no-root-server
+client = 7-verify-custom-success-no-root-client
+
+[7-verify-custom-success-no-root-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+
+[7-verify-custom-success-no-root-client]
+CipherString = DEFAULT
+VerifyMode = Peer
+
+
+[test-7]
+ClientVerifyCallback = AcceptAll
+ExpectedResult = Success
+
+
+# ===========================================================
+
+[8-verify-custom-fail-no-root]
+ssl_conf = 8-verify-custom-fail-no-root-ssl
+
+[8-verify-custom-fail-no-root-ssl]
+server = 8-verify-custom-fail-no-root-server
+client = 8-verify-custom-fail-no-root-client
+
+[8-verify-custom-fail-no-root-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+
+[8-verify-custom-fail-no-root-client]
+CipherString = DEFAULT
+VerifyMode = Peer
+
+
+[test-8]
+ClientAlert = HandshakeFailure
+ClientVerifyCallback = RejectAll
+ExpectedResult = ClientFail
+
+
--- /dev/null
+# -*- mode: perl; -*-
+
+## SSL test configurations
+
+package ssltests;
+
+our @tests = (
+
+ # Sanity-check that verification indeed succeeds without the
+ # restrictive callback.
+ {
+ name => "verify-success",
+ server => { },
+ client => { },
+ test => { "ExpectedResult" => "Success" },
+ },
+
+ # Same test as above but with a custom callback that always fails.
+ {
+ name => "verify-custom-reject",
+ server => { },
+ client => { },
+ test => {
+ "ClientVerifyCallback" => "RejectAll",
+ "ExpectedResult" => "ClientFail",
+ "ClientAlert" => "HandshakeFailure",
+ },
+ },
+
+ # Same test as above but with a custom callback that always succeeds.
+ {
+ name => "verify-custom-allow",
+ server => { },
+ client => { },
+ test => {
+ "ClientVerifyCallback" => "AcceptAll",
+ "ExpectedResult" => "Success",
+ },
+ },
+
+ # Sanity-check that verification indeed succeeds if peer verification
+ # is not requested.
+ {
+ name => "noverify-success",
+ server => { },
+ client => {
+ "VerifyMode" => undef,
+ "VerifyCAFile" => undef,
+ },
+ test => { "ExpectedResult" => "Success" },
+ },
+
+ # Same test as above but with a custom callback that always fails.
+ # The callback return has no impact on handshake success in this mode.
+ {
+ name => "noverify-ignore-custom-reject",
+ server => { },
+ client => {
+ "VerifyMode" => undef,
+ "VerifyCAFile" => undef,
+ },
+ test => {
+ "ClientVerifyCallback" => "RejectAll",
+ "ExpectedResult" => "Success",
+ },
+ },
+
+ # Same test as above but with a custom callback that always succeeds.
+ # The callback return has no impact on handshake success in this mode.
+ {
+ name => "noverify-accept-custom-allow",
+ server => { },
+ client => {
+ "VerifyMode" => undef,
+ "VerifyCAFile" => undef,
+ },
+ test => {
+ "ClientVerifyCallback" => "AcceptAll",
+ "ExpectedResult" => "Success",
+ },
+ },
+
+ # Sanity-check that verification indeed fails without the
+ # permissive callback.
+ {
+ name => "verify-fail-no-root",
+ server => { },
+ client => {
+ # Don't set up the client root file.
+ "VerifyCAFile" => undef,
+ },
+ test => {
+ "ExpectedResult" => "ClientFail",
+ "ClientAlert" => "UnknownCA",
+ },
+ },
+
+ # Same test as above but with a custom callback that always succeeds.
+ {
+ name => "verify-custom-success-no-root",
+ server => { },
+ client => {
+ "VerifyCAFile" => undef,
+ },
+ test => {
+ "ClientVerifyCallback" => "AcceptAll",
+ "ExpectedResult" => "Success"
+ },
+ },
+
+ # Same test as above but with a custom callback that always fails.
+ {
+ name => "verify-custom-fail-no-root",
+ server => { },
+ client => {
+ "VerifyCAFile" => undef,
+ },
+ test => {
+ "ClientVerifyCallback" => "RejectAll",
+ "ExpectedResult" => "ClientFail",
+ "ClientAlert" => "HandshakeFailure",
+ },
+ },
+
+
+
+);
{
if (result.result != test_ctx->expected_result) {
fprintf(stderr, "ExpectedResult mismatch: expected %s, got %s.\n",
- ssl_test_result_t_name(test_ctx->expected_result),
- ssl_test_result_t_name(result.result));
+ ssl_test_result_name(test_ctx->expected_result),
+ ssl_test_result_name(result.result));
return 0;
}
return 1;
if (test_ctx == NULL)
goto err;
- result = do_handshake(server_ctx, client_ctx);
+ result = do_handshake(server_ctx, client_ctx, test_ctx);
ret = check_test(result, test_ctx);
return 1;
}
-const char *ssl_test_result_t_name(ssl_test_result_t result)
+const char *ssl_test_result_name(ssl_test_result_t result)
{
return enum_name(ssl_test_results, OSSL_NELEM(ssl_test_results), result);
}
static const test_enum ssl_alerts[] = {
{"UnknownCA", SSL_AD_UNKNOWN_CA},
+ {"HandshakeFailure", SSL_AD_HANDSHAKE_FAILURE},
};
__owur static int parse_alert(int *alert, const char *value)
return enum_name(ssl_protocols, OSSL_NELEM(ssl_protocols), protocol);
}
+/***********************/
+/* CertVerifyCallback. */
+/***********************/
+
+static const test_enum ssl_verify_callbacks[] = {
+ {"None", SSL_TEST_VERIFY_NONE},
+ {"AcceptAll", SSL_TEST_VERIFY_ACCEPT_ALL},
+ {"RejectAll", SSL_TEST_VERIFY_REJECT_ALL},
+};
+
+__owur static int parse_client_verify_callback(SSL_TEST_CTX *test_ctx,
+ const char *value)
+{
+ int ret_value;
+ if (!parse_enum(ssl_verify_callbacks, OSSL_NELEM(ssl_verify_callbacks),
+ &ret_value, value)) {
+ return 0;
+ }
+ test_ctx->client_verify_callback = ret_value;
+ return 1;
+}
+
+const char *ssl_verify_callback_name(ssl_verify_callback_t callback)
+{
+ return enum_name(ssl_verify_callbacks, OSSL_NELEM(ssl_verify_callbacks),
+ callback);
+}
+
/*************************************************************/
/* Known test options and their corresponding parse methods. */
{ "ClientAlert", &parse_client_alert },
{ "ServerAlert", &parse_server_alert },
{ "Protocol", &parse_protocol },
+ { "ClientVerifyCallback", &parse_client_verify_callback },
};
SSL_TEST_CTX *ret;
ret = OPENSSL_zalloc(sizeof(*ret));
OPENSSL_assert(ret != NULL);
- ret->expected_result = SSL_TEST_SUCCESS;
return ret;
}
#include <openssl/ssl.h>
typedef enum {
- SSL_TEST_SUCCESS, /* Default */
+ SSL_TEST_SUCCESS = 0, /* Default */
SSL_TEST_SERVER_FAIL,
SSL_TEST_CLIENT_FAIL,
SSL_TEST_INTERNAL_ERROR
} ssl_test_result_t;
+typedef enum {
+ SSL_TEST_VERIFY_NONE = 0, /* Default */
+ SSL_TEST_VERIFY_ACCEPT_ALL,
+ SSL_TEST_VERIFY_REJECT_ALL
+} ssl_verify_callback_t;
+
typedef struct ssl_test_ctx {
/* Test expectations. */
/* Defaults to SUCCESS. */
/* Negotiated protocol version. 0 if no expectation. */
/* See ssl.h for protocol versions. */
int protocol;
+ /* One of a number of predefined custom callbacks. */
+ ssl_verify_callback_t client_verify_callback;
} SSL_TEST_CTX;
-const char *ssl_test_result_t_name(ssl_test_result_t result);
+const char *ssl_test_result_name(ssl_test_result_t result);
const char *ssl_alert_name(int alert);
const char *ssl_protocol_name(int protocol);
+const char *ssl_verify_callback_name(ssl_verify_callback_t verify_callback);
/*
* Load the test case context from |conf|.
{
if (ctx->expected_result != ctx2->expected_result) {
fprintf(stderr, "ExpectedResult mismatch: %s vs %s.\n",
- ssl_test_result_t_name(ctx->expected_result),
- ssl_test_result_t_name(ctx2->expected_result));
+ ssl_test_result_name(ctx->expected_result),
+ ssl_test_result_name(ctx2->expected_result));
return 0;
}
if (ctx->client_alert != ctx2->client_alert) {
fprintf(stderr, "ClientAlert mismatch: %s vs %s.\n",
- ssl_alert_name(ctx->expected_result),
- ssl_alert_name(ctx2->expected_result));
+ ssl_alert_name(ctx->client_alert),
+ ssl_alert_name(ctx2->client_alert));
return 0;
}
if (ctx->server_alert != ctx2->server_alert) {
fprintf(stderr, "ServerAlert mismatch: %s vs %s.\n",
- ssl_alert_name(ctx->expected_result),
- ssl_alert_name(ctx2->expected_result));
+ ssl_alert_name(ctx->server_alert),
+ ssl_alert_name(ctx2->server_alert));
return 0;
}
if (ctx->protocol != ctx2->protocol) {
fprintf(stderr, "ClientAlert mismatch: %s vs %s.\n",
- ssl_protocol_name(ctx->expected_result),
- ssl_protocol_name(ctx2->expected_result));
+ ssl_protocol_name(ctx->protocol),
+ ssl_protocol_name(ctx2->protocol));
+ return 0;
+ }
+ if (ctx->client_verify_callback != ctx2->client_verify_callback) {
+ fprintf(stderr, "ClientVerifyCallback mismatch: %s vs %s.\n",
+ ssl_verify_callback_name(ctx->client_verify_callback),
+ ssl_verify_callback_name(ctx2->client_verify_callback));
return 0;
}
fixture.expected_ctx->client_alert = SSL_AD_UNKNOWN_CA;
fixture.expected_ctx->server_alert = 0; /* No alert. */
fixture.expected_ctx->protocol = TLS1_1_VERSION;
+ fixture.expected_ctx->client_verify_callback = SSL_TEST_VERIFY_REJECT_ALL,
EXECUTE_SSL_TEST_CTX_TEST();
}
"ssltest_unknown_expected_result",
"ssltest_unknown_alert",
"ssltest_unknown_protocol",
+ "ssltest_unknown_verify_callback",
};
static int test_bad_configuration(int idx)
ExpectedResult = ServerFail
ClientAlert = UnknownCA
Protocol = TLSv1.1
+ClientVerifyCallback = RejectAll
[ssltest_unknown_option]
UnknownOption = Foo
[ssltest_unknown_protocol]
Protocol = Foo
+
+[ssltest_unknown_verify_callback]
+ClientVerifyCallback = Foo
struct app_verify_arg {
char *string;
int app_verify;
- int allow_proxy_certs;
- char *proxy_auth;
- char *proxy_cond;
};
#ifndef OPENSSL_NO_DH
#endif
fprintf(stderr, " -server_auth - check server certificate\n");
fprintf(stderr, " -client_auth - do client authentication\n");
- fprintf(stderr, " -proxy - allow proxy certificates\n");
- fprintf(stderr, " -proxy_auth <val> - set proxy policy rights\n");
- fprintf(stderr,
- " -proxy_cond <val> - expression to test proxy policy rights\n");
fprintf(stderr, " -v - more output\n");
fprintf(stderr, " -d - debug output\n");
fprintf(stderr, " -reuse - use session-id reuse\n");
int client_auth = 0;
int server_auth = 0, i;
struct app_verify_arg app_verify_arg =
- { APP_CALLBACK_STRING, 0, 0, NULL, NULL };
+ { APP_CALLBACK_STRING, 0 };
char *p;
SSL_CTX *c_ctx = NULL;
const SSL_METHOD *meth = NULL;
server_auth = 1;
else if (strcmp(*argv, "-client_auth") == 0)
client_auth = 1;
- else if (strcmp(*argv, "-proxy_auth") == 0) {
- if (--argc < 1)
- goto bad;
- app_verify_arg.proxy_auth = *(++argv);
- } else if (strcmp(*argv, "-proxy_cond") == 0) {
- if (--argc < 1)
- goto bad;
- app_verify_arg.proxy_cond = *(++argv);
- } else if (strcmp(*argv, "-v") == 0)
+ else if (strcmp(*argv, "-v") == 0)
verbose = 1;
else if (strcmp(*argv, "-d") == 0)
debug = 1;
#endif
else if (strcmp(*argv, "-app_verify") == 0) {
app_verify_arg.app_verify = 1;
- } else if (strcmp(*argv, "-proxy") == 0) {
- app_verify_arg.allow_proxy_certs = 1;
}
#ifndef OPENSSL_NO_NEXTPROTONEG
else if (strcmp(*argv, "-npn_client") == 0) {
return (ret);
}
-static CRYPTO_ONCE proxy_auth_ex_data_once = CRYPTO_ONCE_STATIC_INIT;
-static volatile int proxy_auth_ex_data_idx = -1;
-
-static void do_get_proxy_auth_ex_data_idx(void)
-{
- proxy_auth_ex_data_idx = X509_STORE_CTX_get_ex_new_index(0,
- "SSLtest for verify callback",
- NULL, NULL, NULL);
-}
-
-static int get_proxy_auth_ex_data_idx(void)
-{
- CRYPTO_THREAD_run_once(&proxy_auth_ex_data_once,
- do_get_proxy_auth_ex_data_idx);
- return proxy_auth_ex_data_idx;
-}
-
static int verify_callback(int ok, X509_STORE_CTX *ctx)
{
char *s, buf[256];
}
}
- if (ok == 1) {
- X509 *xs = X509_STORE_CTX_get_current_cert(ctx);
- if (X509_get_extension_flags(xs) & EXFLAG_PROXY) {
- unsigned int *letters = X509_STORE_CTX_get_ex_data(ctx,
- get_proxy_auth_ex_data_idx
- ());
-
- if (letters) {
- int found_any = 0;
- int i;
- PROXY_CERT_INFO_EXTENSION *pci =
- X509_get_ext_d2i(xs, NID_proxyCertInfo,
- NULL, NULL);
-
- switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage)) {
- case NID_Independent:
- /*
- * Completely meaningless in this program, as there's no
- * way to grant explicit rights to a specific PrC.
- * Basically, using id-ppl-Independent is the perfect way
- * to grant no rights at all.
- */
- fprintf(stderr, " Independent proxy certificate");
- for (i = 0; i < 26; i++)
- letters[i] = 0;
- break;
- case NID_id_ppl_inheritAll:
- /*
- * This is basically a NOP, we simply let the current
- * rights stand as they are.
- */
- fprintf(stderr, " Proxy certificate inherits all");
- break;
- default:
- s = (char *)
- pci->proxyPolicy->policy->data;
- i = pci->proxyPolicy->policy->length;
-
- /*
- * The algorithm works as follows: it is assumed that
- * previous iterations or the initial granted rights has
- * already set some elements of `letters'. What we need
- * to do is to clear those that weren't granted by the
- * current PrC as well. The easiest way to do this is to
- * add 1 to all the elements whose letters are given with
- * the current policy. That way, all elements that are
- * set by the current policy and were already set by
- * earlier policies and through the original grant of
- * rights will get the value 2 or higher. The last thing
- * to do is to sweep through `letters' and keep the
- * elements having the value 2 as set, and clear all the
- * others.
- */
-
- printf(" Certificate proxy rights = %*.*s", i,
- i, s);
- while (i-- > 0) {
- int c = *s++;
- if (isascii(c) && isalpha(c)) {
- if (islower(c))
- c = toupper(c);
- letters[c - 'A']++;
- }
- }
- for (i = 0; i < 26; i++)
- if (letters[i] < 2)
- letters[i] = 0;
- else
- letters[i] = 1;
- }
-
- found_any = 0;
- printf(", resulting proxy rights = ");
- for (i = 0; i < 26; i++)
- if (letters[i]) {
- printf("%c", i + 'A');
- found_any = 1;
- }
- if (!found_any)
- printf("none");
- printf("\n");
-
- PROXY_CERT_INFO_EXTENSION_free(pci);
- }
- }
- }
-
return (ok);
}
-static void process_proxy_debug(int indent, const char *format, ...)
-{
- /* That's 80 > */
- static const char indentation[] =
- ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
- ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>";
- char my_format[256];
- va_list args;
-
- BIO_snprintf(my_format, sizeof(my_format), "%*.*s %s",
- indent, indent, indentation, format);
-
- va_start(args, format);
- vfprintf(stderr, my_format, args);
- va_end(args);
-}
-
-/*-
- * Priority levels:
- * 0 [!]var, ()
- * 1 & ^
- * 2 |
- */
-static int process_proxy_cond_adders(unsigned int letters[26],
- const char *cond, const char **cond_end,
- int *pos, int indent);
-static int process_proxy_cond_val(unsigned int letters[26], const char *cond,
- const char **cond_end, int *pos, int indent)
-{
- int c;
- int ok = 1;
- int negate = 0;
-
- while (isspace((int)*cond)) {
- cond++;
- (*pos)++;
- }
- c = *cond;
-
- if (debug)
- process_proxy_debug(indent,
- "Start process_proxy_cond_val at position %d: %s\n",
- *pos, cond);
-
- while (c == '!') {
- negate = !negate;
- cond++;
- (*pos)++;
- while (isspace((int)*cond)) {
- cond++;
- (*pos)++;
- }
- c = *cond;
- }
-
- if (c == '(') {
- cond++;
- (*pos)++;
- ok = process_proxy_cond_adders(letters, cond, cond_end, pos,
- indent + 1);
- cond = *cond_end;
- if (ok < 0)
- goto end;
- while (isspace((int)*cond)) {
- cond++;
- (*pos)++;
- }
- c = *cond;
- if (c != ')') {
- fprintf(stderr,
- "Weird condition character in position %d: "
- "%c\n", *pos, c);
- ok = -1;
- goto end;
- }
- cond++;
- (*pos)++;
- } else if (isascii(c) && isalpha(c)) {
- if (islower(c))
- c = toupper(c);
- ok = letters[c - 'A'];
- cond++;
- (*pos)++;
- } else {
- fprintf(stderr,
- "Weird condition character in position %d: " "%c\n", *pos, c);
- ok = -1;
- goto end;
- }
- end:
- *cond_end = cond;
- if (ok >= 0 && negate)
- ok = !ok;
-
- if (debug)
- process_proxy_debug(indent,
- "End process_proxy_cond_val at position %d: %s, returning %d\n",
- *pos, cond, ok);
-
- return ok;
-}
-
-static int process_proxy_cond_multipliers(unsigned int letters[26],
- const char *cond,
- const char **cond_end, int *pos,
- int indent)
-{
- int ok;
- char c;
-
- if (debug)
- process_proxy_debug(indent,
- "Start process_proxy_cond_multipliers at position %d: %s\n",
- *pos, cond);
-
- ok = process_proxy_cond_val(letters, cond, cond_end, pos, indent + 1);
- cond = *cond_end;
- if (ok < 0)
- goto end;
-
- while (ok >= 0) {
- while (isspace((int)*cond)) {
- cond++;
- (*pos)++;
- }
- c = *cond;
-
- switch (c) {
- case '&':
- case '^':
- {
- int save_ok = ok;
-
- cond++;
- (*pos)++;
- ok = process_proxy_cond_val(letters,
- cond, cond_end, pos, indent + 1);
- cond = *cond_end;
- if (ok < 0)
- break;
-
- switch (c) {
- case '&':
- ok &= save_ok;
- break;
- case '^':
- ok ^= save_ok;
- break;
- default:
- fprintf(stderr, "SOMETHING IS SERIOUSLY WRONG!"
- " STOPPING\n");
- EXIT(1);
- }
- }
- break;
- default:
- goto end;
- }
- }
- end:
- if (debug)
- process_proxy_debug(indent,
- "End process_proxy_cond_multipliers at position %d: %s, returning %d\n",
- *pos, cond, ok);
-
- *cond_end = cond;
- return ok;
-}
-
-static int process_proxy_cond_adders(unsigned int letters[26],
- const char *cond, const char **cond_end,
- int *pos, int indent)
-{
- int ok;
- char c;
-
- if (debug)
- process_proxy_debug(indent,
- "Start process_proxy_cond_adders at position %d: %s\n",
- *pos, cond);
-
- ok = process_proxy_cond_multipliers(letters, cond, cond_end, pos,
- indent + 1);
- cond = *cond_end;
- if (ok < 0)
- goto end;
-
- while (ok >= 0) {
- while (isspace((int)*cond)) {
- cond++;
- (*pos)++;
- }
- c = *cond;
-
- switch (c) {
- case '|':
- {
- int save_ok = ok;
-
- cond++;
- (*pos)++;
- ok = process_proxy_cond_multipliers(letters,
- cond, cond_end, pos,
- indent + 1);
- cond = *cond_end;
- if (ok < 0)
- break;
-
- switch (c) {
- case '|':
- ok |= save_ok;
- break;
- default:
- fprintf(stderr, "SOMETHING IS SERIOUSLY WRONG!"
- " STOPPING\n");
- EXIT(1);
- }
- }
- break;
- default:
- goto end;
- }
- }
- end:
- if (debug)
- process_proxy_debug(indent,
- "End process_proxy_cond_adders at position %d: %s, returning %d\n",
- *pos, cond, ok);
-
- *cond_end = cond;
- return ok;
-}
-
-static int process_proxy_cond(unsigned int letters[26],
- const char *cond, const char **cond_end)
-{
- int pos = 1;
- return process_proxy_cond_adders(letters, cond, cond_end, &pos, 1);
-}
-
static int app_verify_callback(X509_STORE_CTX *ctx, void *arg)
{
int ok = 1;
struct app_verify_arg *cb_arg = arg;
- unsigned int letters[26]; /* only used with proxy_auth */
if (cb_arg->app_verify) {
char *s = NULL, buf[256];
}
return (1);
}
- if (cb_arg->proxy_auth) {
- int found_any = 0, i;
- char *sp;
-
- for (i = 0; i < 26; i++)
- letters[i] = 0;
- for (sp = cb_arg->proxy_auth; *sp; sp++) {
- int c = *sp;
- if (isascii(c) && isalpha(c)) {
- if (islower(c))
- c = toupper(c);
- letters[c - 'A'] = 1;
- }
- }
- printf(" Initial proxy rights = ");
- for (i = 0; i < 26; i++)
- if (letters[i]) {
- printf("%c", i + 'A');
- found_any = 1;
- }
- if (!found_any)
- printf("none");
- printf("\n");
-
- X509_STORE_CTX_set_ex_data(ctx,
- get_proxy_auth_ex_data_idx(), letters);
- }
- if (cb_arg->allow_proxy_certs) {
- X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS);
- }
ok = X509_verify_cert(ctx);
- if (cb_arg->proxy_auth) {
- if (ok > 0) {
- const char *cond_end = NULL;
-
- ok = process_proxy_cond(letters, cb_arg->proxy_cond, &cond_end);
-
- if (ok < 0)
- EXIT(3);
- if (*cond_end) {
- fprintf(stderr,
- "Stopped processing condition before it's end.\n");
- ok = 0;
- }
- if (!ok)
- fprintf(stderr,
- "Proxy rights check with condition '%s' invalid\n",
- cb_arg->proxy_cond);
- else
- printf("Proxy rights check with condition '%s' ok\n",
- cb_arg->proxy_cond);
- }
- }
return (ok);
}