|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* Copyright (C) 2000-2016 Free Software Foundation, Inc.
|
|
Packit Service |
4684c1 |
* Copyright (C) 2013-2016 Nikos Mavrogiannopoulos
|
|
Packit Service |
4684c1 |
* Copyright (C) 2015-2017 Red Hat, Inc.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This file is part of GnuTLS.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* GnuTLS is free software: you can redistribute it and/or modify
|
|
Packit Service |
4684c1 |
* it under the terms of the GNU General Public License as published by
|
|
Packit Service |
4684c1 |
* the Free Software Foundation, either version 3 of the License, or
|
|
Packit Service |
4684c1 |
* (at your option) any later version.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* GnuTLS is distributed in the hope that it will be useful,
|
|
Packit Service |
4684c1 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
4684c1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
4684c1 |
* GNU General Public License for more details.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
4684c1 |
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include <config.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include <stdio.h>
|
|
Packit Service |
4684c1 |
#include <errno.h>
|
|
Packit Service |
4684c1 |
#include <stdlib.h>
|
|
Packit Service |
4684c1 |
#include <sys/types.h>
|
|
Packit Service |
4684c1 |
#include <string.h>
|
|
Packit Service |
4684c1 |
#include <sys/time.h>
|
|
Packit Service |
4684c1 |
#include <sys/stat.h>
|
|
Packit Service |
4684c1 |
#if HAVE_SYS_SOCKET_H
|
|
Packit Service |
4684c1 |
#include <sys/socket.h>
|
|
Packit Service |
4684c1 |
#elif HAVE_WS2TCPIP_H
|
|
Packit Service |
4684c1 |
#include <ws2tcpip.h>
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
#include <sys/select.h>
|
|
Packit Service |
4684c1 |
#include <unistd.h>
|
|
Packit Service |
4684c1 |
#include <stdint.h>
|
|
Packit Service |
4684c1 |
#include <stdbool.h>
|
|
Packit Service |
4684c1 |
#include <fcntl.h>
|
|
Packit Service |
4684c1 |
#include <netdb.h>
|
|
Packit Service |
4684c1 |
#include <ctype.h>
|
|
Packit Service |
4684c1 |
#include <assert.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Get TCP_FASTOPEN */
|
|
Packit Service |
4684c1 |
#ifdef HAVE_NETINET_TCP_H
|
|
Packit Service |
4684c1 |
#include <netinet/tcp.h>
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include <gnutls/gnutls.h>
|
|
Packit Service |
4684c1 |
#include <gnutls/abstract.h>
|
|
Packit Service |
4684c1 |
#include <gnutls/dtls.h>
|
|
Packit Service |
4684c1 |
#include <gnutls/x509.h>
|
|
Packit Service |
4684c1 |
#include <gnutls/pkcs11.h>
|
|
Packit Service |
4684c1 |
#include <gnutls/crypto.h>
|
|
Packit Service |
4684c1 |
#include <gnutls/socket.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Gnulib portability files. */
|
|
Packit Service |
4684c1 |
#include <read-file.h>
|
|
Packit Service |
4684c1 |
#include <getpass.h>
|
|
Packit Service |
4684c1 |
#include <minmax.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include "sockets.h"
|
|
Packit Service |
4684c1 |
#include "benchmark.h"
|
|
Packit Service |
4684c1 |
#include "inline_cmds.h"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef HAVE_DANE
|
|
Packit Service |
4684c1 |
#include <gnutls/dane.h>
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include <common.h>
|
|
Packit Service |
4684c1 |
#include <socket.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include <cli-args.h>
|
|
Packit Service |
4684c1 |
#include <ocsptool-common.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define MAX_BUF 4096
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* global stuff here */
|
|
Packit Service |
4684c1 |
int resume, starttls, insecure, ranges, rehandshake, udp, mtu,
|
|
Packit Service |
4684c1 |
inline_commands, waitresumption;
|
|
Packit Service |
4684c1 |
unsigned int global_vflags = 0;
|
|
Packit Service |
4684c1 |
char *hostname = NULL;
|
|
Packit Service |
4684c1 |
char service[32]="";
|
|
Packit Service |
4684c1 |
int record_max_size;
|
|
Packit Service |
4684c1 |
int crlf;
|
|
Packit Service |
4684c1 |
int fastopen;
|
|
Packit Service |
4684c1 |
unsigned int verbose = 0;
|
|
Packit Service |
4684c1 |
int print_cert;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
const char *srp_passwd = NULL;
|
|
Packit Service |
4684c1 |
const char *srp_username = NULL;
|
|
Packit Service |
4684c1 |
const char *x509_keyfile = NULL;
|
|
Packit Service |
4684c1 |
const char *x509_certfile = NULL;
|
|
Packit Service |
4684c1 |
const char *x509_cafile = NULL;
|
|
Packit Service |
4684c1 |
const char *x509_crlfile = NULL;
|
|
Packit Service |
4684c1 |
static int x509ctype;
|
|
Packit Service |
4684c1 |
const char *rawpk_keyfile = NULL;
|
|
Packit Service |
4684c1 |
const char *rawpk_file = NULL;
|
|
Packit Service |
4684c1 |
static int disable_extensions;
|
|
Packit Service |
4684c1 |
static int disable_sni;
|
|
Packit Service |
4684c1 |
static unsigned int init_flags = GNUTLS_CLIENT | GNUTLS_ENABLE_RAWPK;
|
|
Packit Service |
4684c1 |
static const char *priorities = NULL;
|
|
Packit Service |
4684c1 |
static const char *inline_commands_prefix;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
const char *psk_username = NULL;
|
|
Packit Service |
4684c1 |
gnutls_datum_t psk_key = { NULL, 0 };
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static gnutls_srp_client_credentials_t srp_cred;
|
|
Packit Service |
4684c1 |
static gnutls_psk_client_credentials_t psk_cred;
|
|
Packit Service |
4684c1 |
static gnutls_anon_client_credentials_t anon_cred;
|
|
Packit Service |
4684c1 |
static gnutls_certificate_credentials_t xcred;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* end of global stuff */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* prototypes */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void check_server_cmd(socket_st * socket, int ret);
|
|
Packit Service |
4684c1 |
static void init_global_tls_stuff(void);
|
|
Packit Service |
4684c1 |
static int cert_verify_ocsp(gnutls_session_t session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define MAX_CRT 6
|
|
Packit Service |
4684c1 |
static unsigned int x509_crt_size;
|
|
Packit Service |
4684c1 |
static gnutls_pcert_st x509_crt[MAX_CRT];
|
|
Packit Service |
4684c1 |
static gnutls_privkey_t x509_key = NULL;
|
|
Packit Service |
4684c1 |
static gnutls_pcert_st rawpk;
|
|
Packit Service |
4684c1 |
static gnutls_privkey_t rawpk_key = NULL;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Load a PKCS #8, PKCS #12 private key or PKCS #11 URL
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static void load_priv_key(gnutls_privkey_t* privkey, const char* key_source)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
gnutls_datum_t data = { NULL, 0 };
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_privkey_init(privkey);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "*** Error initializing key: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_privkey_set_pin_function(*privkey, pin_callback,
|
|
Packit Service |
4684c1 |
NULL);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_url_is_supported(key_source) != 0) {
|
|
Packit Service |
4684c1 |
ret = gnutls_privkey_import_url(*privkey, key_source, 0);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Error loading url: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
ret = gnutls_load_file(key_source, &data);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Error loading key file.\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_privkey_import_x509_raw(*privkey, &data,
|
|
Packit Service |
4684c1 |
x509ctype, NULL, 0);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Error importing key: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_free(data.data);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Load the X509 certificate and the private key.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static void load_x509_keys(void)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
unsigned int crt_num;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
unsigned int i;
|
|
Packit Service |
4684c1 |
gnutls_datum_t data = { NULL, 0 };
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_t crt_list[MAX_CRT];
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (x509_certfile != NULL && x509_keyfile != NULL) {
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_PKCS11
|
|
Packit Service |
4684c1 |
if (strncmp(x509_certfile, "pkcs11:", 7) == 0) {
|
|
Packit Service |
4684c1 |
crt_num = 1;
|
|
Packit Service |
4684c1 |
ret = gnutls_x509_crt_init(&crt_list[0]);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Memory error\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_set_pin_function(crt_list[0],
|
|
Packit Service |
4684c1 |
pin_callback,
|
|
Packit Service |
4684c1 |
NULL);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_import_pkcs11_url(crt_list[0],
|
|
Packit Service |
4684c1 |
x509_certfile,
|
|
Packit Service |
4684c1 |
0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_import_pkcs11_url
|
|
Packit Service |
4684c1 |
(crt_list[0], x509_certfile,
|
|
Packit Service |
4684c1 |
GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Error loading cert file.\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
x509_crt_size = 1;
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
#endif /* ENABLE_PKCS11 */
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_load_file(x509_certfile, &data);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Error loading cert file.\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
crt_num = MAX_CRT;
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_list_import(crt_list, &crt_num,
|
|
Packit Service |
4684c1 |
&data, x509ctype,
|
|
Packit Service |
4684c1 |
GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Error loading cert file: Too many certs %d\n",
|
|
Packit Service |
4684c1 |
crt_num);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Error loading cert file: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
x509_crt_size = ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i = 0; i < x509_crt_size; i++) {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_pcert_import_x509(&x509_crt[i],
|
|
Packit Service |
4684c1 |
crt_list[i], 0);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Error importing crt to pcert: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_deinit(crt_list[i]);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_free(data.data);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
load_priv_key(&x509_key, x509_keyfile);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
log_msg(stdout,
|
|
Packit Service |
4684c1 |
"Processed %d client X.509 certificates...\n",
|
|
Packit Service |
4684c1 |
x509_crt_size);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Load the raw public key and corresponding private key.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static void load_rawpk_keys(void)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
gnutls_datum_t data = { NULL, 0 };
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (rawpk_file != NULL && rawpk_keyfile != NULL) {
|
|
Packit Service |
4684c1 |
// First we load the raw public key
|
|
Packit Service |
4684c1 |
ret = gnutls_load_file(rawpk_file, &data);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Error loading cert file.\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_pcert_import_rawpk_raw(&rawpk, &data, x509ctype, 0, 0);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Error importing rawpk to pcert: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_free(data.data);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
// Secondly, we load the private key corresponding to the raw pk
|
|
Packit Service |
4684c1 |
load_priv_key(&rawpk_key, rawpk_keyfile);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
log_msg(stdout,
|
|
Packit Service |
4684c1 |
"Processed %d client raw public key pair...\n", 1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define IS_NEWLINE(x) ((x[0] == '\n') || (x[0] == '\r'))
|
|
Packit Service |
4684c1 |
static int read_yesno(const char *input_str)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
char input[128];
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
fputs(input_str, stderr);
|
|
Packit Service |
4684c1 |
if (fgets(input, sizeof(input), stdin) == NULL)
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (IS_NEWLINE(input))
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (input[0] == 'y' || input[0] == 'Y')
|
|
Packit Service |
4684c1 |
return 1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void try_save_cert(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
const gnutls_datum_t *cert_list;
|
|
Packit Service |
4684c1 |
unsigned int cert_list_size = 0;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
unsigned i;
|
|
Packit Service |
4684c1 |
gnutls_datum_t t;
|
|
Packit Service |
4684c1 |
FILE *fp;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
|
|
Packit Service |
4684c1 |
if (cert_list_size == 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "no certificates sent by server!\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
fp = fopen(OPT_ARG(SAVE_CERT), "w");
|
|
Packit Service |
4684c1 |
if (fp == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "could not open %s\n", OPT_ARG(SAVE_CERT));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i=0;i
|
|
Packit Service |
4684c1 |
ret = gnutls_pem_base64_encode_alloc("CERTIFICATE", &cert_list[i], &t);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "error[%d]: %s\n", __LINE__,
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
fwrite(t.data, t.size, 1, fp);
|
|
Packit Service |
4684c1 |
gnutls_free(t.data);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
fclose(fp);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void try_save_ocsp_status(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
unsigned int cert_num = 0;
|
|
Packit Service |
4684c1 |
gnutls_certificate_get_peers(session, &cert_num);
|
|
Packit Service |
4684c1 |
if (cert_num == 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "no certificates sent by server, so can't get OCSP status!\n");
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
const char *path;
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_fmt_t type;
|
|
Packit Service |
4684c1 |
unsigned int max_out;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This function is called if exactly one of SAVE_OCSP and
|
|
Packit Service |
4684c1 |
* SAVE_OCSP_MULTI is set. */
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SAVE_OCSP))
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
path = OPT_ARG(SAVE_OCSP);
|
|
Packit Service |
4684c1 |
type = GNUTLS_X509_FMT_DER;
|
|
Packit Service |
4684c1 |
max_out = 1;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
path = OPT_ARG(SAVE_OCSP_MULTI);
|
|
Packit Service |
4684c1 |
type = GNUTLS_X509_FMT_PEM;
|
|
Packit Service |
4684c1 |
max_out = cert_num;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
FILE *fp = fopen(path, "w");
|
|
Packit Service |
4684c1 |
if (fp == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "could not open %s for writing\n", path);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (unsigned int i = 0; i < max_out; i++) {
|
|
Packit Service |
4684c1 |
gnutls_datum_t oresp;
|
|
Packit Service |
4684c1 |
int ret = gnutls_ocsp_status_request_get2(session, i, &oresp);
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "no OCSP response for certificate %u\n", i);
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
} else if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "error getting OCSP response %u: %s\n",
|
|
Packit Service |
4684c1 |
i, gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (type == GNUTLS_X509_FMT_DER) {
|
|
Packit Service |
4684c1 |
/* on success the return value is equal to the
|
|
Packit Service |
4684c1 |
* number of items (third parameter) */
|
|
Packit Service |
4684c1 |
if (fwrite(oresp.data, oresp.size, 1, fp) != 1) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "writing to %s failed\n", path);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_datum_t t;
|
|
Packit Service |
4684c1 |
ret = gnutls_pem_base64_encode_alloc("OCSP RESPONSE",
|
|
Packit Service |
4684c1 |
&oresp, &t);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "error allocating PEM OCSP response: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* on success the return value is equal to the number
|
|
Packit Service |
4684c1 |
* of items (third parameter) */
|
|
Packit Service |
4684c1 |
if (fwrite(t.data, t.size, 1, fp) != 1) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "writing to %s failed\n", path);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
gnutls_free(t.data);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (fclose(fp) != 0) {
|
|
Packit Service |
4684c1 |
perror("failed to close OCSP save file");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int cert_verify_callback(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int rc;
|
|
Packit Service |
4684c1 |
unsigned int status = 0;
|
|
Packit Service |
4684c1 |
int ssh = ENABLED_OPT(TOFU);
|
|
Packit Service |
4684c1 |
int strictssh = ENABLED_OPT(STRICT_TOFU);
|
|
Packit Service |
4684c1 |
int dane = ENABLED_OPT(DANE);
|
|
Packit Service |
4684c1 |
int ca_verify = ENABLED_OPT(CA_VERIFICATION);
|
|
Packit Service |
4684c1 |
const char *txt_service;
|
|
Packit Service |
4684c1 |
const char *host;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* On an session with TOFU the PKI/DANE verification
|
|
Packit Service |
4684c1 |
* become advisory.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (strictssh) {
|
|
Packit Service |
4684c1 |
ssh = strictssh;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(VERIFY_HOSTNAME)) {
|
|
Packit Service |
4684c1 |
host = OPT_ARG(VERIFY_HOSTNAME);
|
|
Packit Service |
4684c1 |
canonicalize_host((char *) host, NULL, 0);
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
host = hostname;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Save certificate and OCSP response */
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SAVE_CERT)) {
|
|
Packit Service |
4684c1 |
try_save_cert(session);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifndef ENABLE_OCSP
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SAVE_OCSP_MULTI) || HAVE_OPT(SAVE_OCSP) || HAVE_OPT(OCSP)) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "OCSP is not supported!\n");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#else
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SAVE_OCSP_MULTI) || HAVE_OPT(SAVE_OCSP)) {
|
|
Packit Service |
4684c1 |
try_save_ocsp_status(session);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
print_cert_info(session, verbose, print_cert);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ca_verify) {
|
|
Packit Service |
4684c1 |
rc = cert_verify(session, host, GNUTLS_KP_TLS_WWW_SERVER);
|
|
Packit Service |
4684c1 |
if (rc == 0) {
|
|
Packit Service |
4684c1 |
log_msg
|
|
Packit Service |
4684c1 |
(stdout, "*** PKI verification of server certificate failed...\n");
|
|
Packit Service |
4684c1 |
if (!insecure && !ssh)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_OCSP
|
|
Packit Service |
4684c1 |
else if (ENABLED_OPT(OCSP) && gnutls_ocsp_status_request_is_checked(session, 0) == 0) { /* off-line verification succeeded. Try OCSP */
|
|
Packit Service |
4684c1 |
rc = cert_verify_ocsp(session);
|
|
Packit Service |
4684c1 |
if (rc == -1) {
|
|
Packit Service |
4684c1 |
log_msg
|
|
Packit Service |
4684c1 |
(stdout, "*** Verifying (with OCSP) server certificate chain failed...\n");
|
|
Packit Service |
4684c1 |
if (!insecure && !ssh)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
} else if (rc == 0)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "*** OCSP: nothing to check.\n");
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
log_msg(stdout, "*** OCSP: verified %d certificate(s).\n", rc);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (dane) { /* try DANE auth */
|
|
Packit Service |
4684c1 |
#ifdef HAVE_DANE
|
|
Packit Service |
4684c1 |
int port;
|
|
Packit Service |
4684c1 |
unsigned vflags = 0;
|
|
Packit Service |
4684c1 |
unsigned int sflags =
|
|
Packit Service |
4684c1 |
ENABLED_OPT(LOCAL_DNS) ? 0 :
|
|
Packit Service |
4684c1 |
DANE_F_IGNORE_LOCAL_RESOLVER;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* if we didn't verify the chain it only makes sense
|
|
Packit Service |
4684c1 |
* to check the end certificate using dane. */
|
|
Packit Service |
4684c1 |
if (ca_verify == 0)
|
|
Packit Service |
4684c1 |
vflags |= DANE_VFLAG_ONLY_CHECK_EE_USAGE;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
port = service_to_port(service, udp?"udp":"tcp");
|
|
Packit Service |
4684c1 |
rc = dane_verify_session_crt(NULL, session, host,
|
|
Packit Service |
4684c1 |
udp ? "udp" : "tcp", port,
|
|
Packit Service |
4684c1 |
sflags, vflags, &status);
|
|
Packit Service |
4684c1 |
if (rc < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** DANE verification error: %s\n",
|
|
Packit Service |
4684c1 |
dane_strerror(rc));
|
|
Packit Service |
4684c1 |
if (!insecure && !ssh)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
gnutls_datum_t out;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
rc = dane_verification_status_print(status, &out,
|
|
Packit Service |
4684c1 |
0);
|
|
Packit Service |
4684c1 |
if (rc < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "*** DANE error: %s\n",
|
|
Packit Service |
4684c1 |
dane_strerror(rc));
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "- DANE: %s\n", out.data);
|
|
Packit Service |
4684c1 |
gnutls_free(out.data);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (status != 0 && !insecure && !ssh)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#else
|
|
Packit Service |
4684c1 |
fprintf(stderr, "*** DANE error: GnuTLS is not compiled with DANE support.\n");
|
|
Packit Service |
4684c1 |
if (!insecure && !ssh)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ssh) { /* try ssh auth */
|
|
Packit Service |
4684c1 |
unsigned int list_size;
|
|
Packit Service |
4684c1 |
const gnutls_datum_t *cert;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cert = gnutls_certificate_get_peers(session, &list_size);
|
|
Packit Service |
4684c1 |
if (cert == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Cannot obtain peer's certificate!\n");
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
txt_service = port_to_service(service, udp?"udp":"tcp");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
rc = gnutls_verify_stored_pubkey(NULL, NULL, host,
|
|
Packit Service |
4684c1 |
txt_service,
|
|
Packit Service |
4684c1 |
GNUTLS_CRT_X509, cert, 0);
|
|
Packit Service |
4684c1 |
if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Host %s (%s) has never been contacted before.\n",
|
|
Packit Service |
4684c1 |
host, txt_service);
|
|
Packit Service |
4684c1 |
if (status == 0)
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Its certificate is valid for %s.\n",
|
|
Packit Service |
4684c1 |
host);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (strictssh)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
rc = read_yesno
|
|
Packit Service |
4684c1 |
("Are you sure you want to trust it? (y/N): ");
|
|
Packit Service |
4684c1 |
if (rc == 0)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
} else if (rc == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Warning: host %s is known and it is associated with a different key.\n",
|
|
Packit Service |
4684c1 |
host);
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"It might be that the server has multiple keys, or an attacker replaced the key to eavesdrop this connection .\n");
|
|
Packit Service |
4684c1 |
if (status == 0)
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Its certificate is valid for %s.\n",
|
|
Packit Service |
4684c1 |
host);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (strictssh)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
rc = read_yesno
|
|
Packit Service |
4684c1 |
("Do you trust the received key? (y/N): ");
|
|
Packit Service |
4684c1 |
if (rc == 0)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
} else if (rc < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"gnutls_verify_stored_pubkey: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(rc));
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (rc != 0) {
|
|
Packit Service |
4684c1 |
rc = gnutls_store_pubkey(NULL, NULL, host,
|
|
Packit Service |
4684c1 |
txt_service,
|
|
Packit Service |
4684c1 |
GNUTLS_CRT_X509, cert, 0,
|
|
Packit Service |
4684c1 |
0);
|
|
Packit Service |
4684c1 |
if (rc < 0)
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Could not store key: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(rc));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This callback should be associated with a session by calling
|
|
Packit Service |
4684c1 |
* gnutls_certificate_client_set_retrieve_function( session, cert_callback),
|
|
Packit Service |
4684c1 |
* before a handshake.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int
|
|
Packit Service |
4684c1 |
cert_callback(gnutls_session_t session,
|
|
Packit Service |
4684c1 |
const gnutls_datum_t * req_ca_rdn, int nreqs,
|
|
Packit Service |
4684c1 |
const gnutls_pk_algorithm_t * sign_algos,
|
|
Packit Service |
4684c1 |
int sign_algos_length, gnutls_pcert_st ** pcert,
|
|
Packit Service |
4684c1 |
unsigned int *pcert_length, gnutls_privkey_t * pkey)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
char issuer_dn[256];
|
|
Packit Service |
4684c1 |
int i, ret, cert_type;
|
|
Packit Service |
4684c1 |
size_t len;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (verbose) {
|
|
Packit Service |
4684c1 |
/* Print the server's trusted CAs
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
if (nreqs > 0)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "- Server's trusted authorities:\n");
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
log_msg
|
|
Packit Service |
4684c1 |
(stdout, "- Server did not send us any trusted authorities names.\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* print the names (if any) */
|
|
Packit Service |
4684c1 |
for (i = 0; i < nreqs; i++) {
|
|
Packit Service |
4684c1 |
len = sizeof(issuer_dn);
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_x509_rdn_get(&req_ca_rdn[i], issuer_dn,
|
|
Packit Service |
4684c1 |
&len;;
|
|
Packit Service |
4684c1 |
if (ret >= 0) {
|
|
Packit Service |
4684c1 |
log_msg(stdout, " [%d]: ", i);
|
|
Packit Service |
4684c1 |
log_msg(stdout, "%s\n", issuer_dn);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Select a certificate and return it.
|
|
Packit Service |
4684c1 |
* The certificate must be of any of the "sign algorithms"
|
|
Packit Service |
4684c1 |
* supported by the server.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cert_type = gnutls_certificate_type_get2(session, GNUTLS_CTYPE_CLIENT);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*pcert_length = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
switch (cert_type) {
|
|
Packit Service |
4684c1 |
case GNUTLS_CRT_X509:
|
|
Packit Service |
4684c1 |
if (x509_crt_size > 0) {
|
|
Packit Service |
4684c1 |
if (x509_key != NULL) {
|
|
Packit Service |
4684c1 |
*pkey = x509_key;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
log_msg
|
|
Packit Service |
4684c1 |
(stdout, "- Could not find a suitable key to send to server\n");
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*pcert_length = x509_crt_size;
|
|
Packit Service |
4684c1 |
*pcert = x509_crt;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
case GNUTLS_CRT_RAWPK:
|
|
Packit Service |
4684c1 |
if (rawpk_key == NULL || rawpk.type != GNUTLS_CRT_RAWPK) {
|
|
Packit Service |
4684c1 |
log_msg
|
|
Packit Service |
4684c1 |
(stdout, "- Could not find a suitable key to send to server\n");
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*pkey = rawpk_key;
|
|
Packit Service |
4684c1 |
*pcert = &rawpk;
|
|
Packit Service |
4684c1 |
*pcert_length = 1;
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
default:
|
|
Packit Service |
4684c1 |
log_msg(stdout, "- Could not retrieve unsupported certificate type %s.\n",
|
|
Packit Service |
4684c1 |
gnutls_certificate_type_get_name(cert_type));
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
log_msg(stdout, "- Successfully sent %u certificate(s) to server.\n",
|
|
Packit Service |
4684c1 |
*pcert_length);
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* initializes a gnutls_session_t with some defaults.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
gnutls_session_t init_tls_session(const char *host)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
const char *err;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
unsigned i;
|
|
Packit Service |
4684c1 |
gnutls_session_t session;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (udp) {
|
|
Packit Service |
4684c1 |
gnutls_init(&session, GNUTLS_DATAGRAM | init_flags);
|
|
Packit Service |
4684c1 |
if (mtu)
|
|
Packit Service |
4684c1 |
gnutls_dtls_set_mtu(session, mtu);
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
gnutls_init(&session, init_flags);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (priorities == NULL) {
|
|
Packit Service |
4684c1 |
ret = gnutls_set_default_priority(session);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error in setting priorities: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
ret = gnutls_priority_set_direct(session, priorities, &err;;
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_INVALID_REQUEST)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Syntax error at: %s\n", err);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error in priorities: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* allow the use of private ciphersuites.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
if (disable_extensions == 0 && disable_sni == 0) {
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SNI_HOSTNAME)) {
|
|
Packit Service |
4684c1 |
const char *sni_host = OPT_ARG(SNI_HOSTNAME);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
canonicalize_host((char *) sni_host, NULL, 0);
|
|
Packit Service |
4684c1 |
gnutls_server_name_set(session, GNUTLS_NAME_DNS, sni_host, strlen(sni_host));
|
|
Packit Service |
4684c1 |
} else if (host != NULL && is_ip(host) == 0)
|
|
Packit Service |
4684c1 |
gnutls_server_name_set(session, GNUTLS_NAME_DNS,
|
|
Packit Service |
4684c1 |
host, strlen(host));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(DH_BITS)) {
|
|
Packit Service |
4684c1 |
#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
|
|
Packit Service |
4684c1 |
gnutls_dh_set_prime_bits(session, OPT_VALUE_DH_BITS);
|
|
Packit Service |
4684c1 |
#else
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Setting DH parameters is not supported\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(ALPN)) {
|
|
Packit Service |
4684c1 |
#ifndef ENABLE_ALPN
|
|
Packit Service |
4684c1 |
fprintf(stderr, "ALPN is not supported\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
#else
|
|
Packit Service |
4684c1 |
unsigned proto_n = STACKCT_OPT(ALPN);
|
|
Packit Service |
4684c1 |
char **protos = (void *) STACKLST_OPT(ALPN);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (proto_n > 1024) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Number of ALPN protocols too large (%d)\n",
|
|
Packit Service |
4684c1 |
proto_n);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_datum_t p[1024];
|
|
Packit Service |
4684c1 |
for (i = 0; i < proto_n; i++) {
|
|
Packit Service |
4684c1 |
p[i].data = (void *) protos[i];
|
|
Packit Service |
4684c1 |
p[i].size = strlen(protos[i]);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
gnutls_alpn_set_protocols(session, p, proto_n, 0);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred);
|
|
Packit Service |
4684c1 |
if (srp_cred)
|
|
Packit Service |
4684c1 |
gnutls_credentials_set(session, GNUTLS_CRD_SRP, srp_cred);
|
|
Packit Service |
4684c1 |
if (psk_cred)
|
|
Packit Service |
4684c1 |
gnutls_credentials_set(session, GNUTLS_CRD_PSK, psk_cred);
|
|
Packit Service |
4684c1 |
gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_retrieve_function2(xcred, cert_callback);
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_verify_function(xcred,
|
|
Packit Service |
4684c1 |
cert_verify_callback);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* use the max record size extension */
|
|
Packit Service |
4684c1 |
if (record_max_size > 0 && disable_extensions == 0) {
|
|
Packit Service |
4684c1 |
if (gnutls_record_set_max_size(session, record_max_size) <
|
|
Packit Service |
4684c1 |
0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Cannot set the maximum record size to %d.\n",
|
|
Packit Service |
4684c1 |
record_max_size);
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Possible values: 512, 1024, 2048, 4096.\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(HEARTBEAT))
|
|
Packit Service |
4684c1 |
gnutls_heartbeat_enable(session,
|
|
Packit Service |
4684c1 |
GNUTLS_HB_PEER_ALLOWED_TO_SEND);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_DTLS_SRTP
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SRTP_PROFILES)) {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_srtp_set_profile_direct(session,
|
|
Packit Service |
4684c1 |
OPT_ARG(SRTP_PROFILES),
|
|
Packit Service |
4684c1 |
&err;;
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_INVALID_REQUEST)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Syntax error at: %s\n", err);
|
|
Packit Service |
4684c1 |
else if (ret != 0)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error in profiles: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
else fprintf(stderr,"DTLS profile set to %s\n",
|
|
Packit Service |
4684c1 |
OPT_ARG(SRTP_PROFILES));
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret != 0) exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return session;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void cmd_parser(int argc, char **argv);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Returns zero if the error code was successfully handled.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static int handle_error(socket_st * hd, int err)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int alert, ret;
|
|
Packit Service |
4684c1 |
const char *err_type, *str;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (err >= 0 || err == GNUTLS_E_AGAIN
|
|
Packit Service |
4684c1 |
|| err == GNUTLS_E_INTERRUPTED)
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_error_is_fatal(err) == 0) {
|
|
Packit Service |
4684c1 |
ret = 0;
|
|
Packit Service |
4684c1 |
err_type = "Non fatal";
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
ret = err;
|
|
Packit Service |
4684c1 |
err_type = "Fatal";
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
str = gnutls_strerror(err);
|
|
Packit Service |
4684c1 |
if (str == NULL)
|
|
Packit Service |
4684c1 |
str = str_unknown;
|
|
Packit Service |
4684c1 |
fprintf(stderr, "*** %s error: %s\n", err_type, str);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (err == GNUTLS_E_WARNING_ALERT_RECEIVED
|
|
Packit Service |
4684c1 |
|| err == GNUTLS_E_FATAL_ALERT_RECEIVED) {
|
|
Packit Service |
4684c1 |
alert = gnutls_alert_get(hd->session);
|
|
Packit Service |
4684c1 |
str = gnutls_alert_get_name(alert);
|
|
Packit Service |
4684c1 |
if (str == NULL)
|
|
Packit Service |
4684c1 |
str = str_unknown;
|
|
Packit Service |
4684c1 |
log_msg(stdout, "*** Received alert [%d]: %s\n", alert, str);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
check_server_cmd(hd, err);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int starttls_alarmed = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifndef _WIN32
|
|
Packit Service |
4684c1 |
static void starttls_alarm(int signum)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
starttls_alarmed = 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void tls_log_func(int level, const char *str)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
fprintf(stderr, "|<%d>| %s", level, str);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define IN_NONE 0
|
|
Packit Service |
4684c1 |
#define IN_KEYBOARD 1
|
|
Packit Service |
4684c1 |
#define IN_NET 2
|
|
Packit Service |
4684c1 |
#define IN_TERM 3
|
|
Packit Service |
4684c1 |
/* returns IN_KEYBOARD for keyboard input and IN_NET for network input
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static int check_net_or_keyboard_input(socket_st * hd, unsigned user_term)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int maxfd;
|
|
Packit Service |
4684c1 |
fd_set rset;
|
|
Packit Service |
4684c1 |
int err;
|
|
Packit Service |
4684c1 |
struct timeval tv;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
FD_ZERO(&rset);
|
|
Packit Service |
4684c1 |
FD_SET(hd->fd, &rset);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifndef _WIN32
|
|
Packit Service |
4684c1 |
if (!user_term) {
|
|
Packit Service |
4684c1 |
FD_SET(fileno(stdin), &rset);
|
|
Packit Service |
4684c1 |
maxfd = MAX(fileno(stdin), hd->fd);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
maxfd = hd->fd;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#else
|
|
Packit Service |
4684c1 |
maxfd = hd->fd;
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
tv.tv_sec = 2;
|
|
Packit Service |
4684c1 |
tv.tv_usec = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (hd->secure == 1)
|
|
Packit Service |
4684c1 |
if (gnutls_record_check_pending(hd->session))
|
|
Packit Service |
4684c1 |
return IN_NET;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
err = select(maxfd + 1, &rset, NULL, NULL, &tv;;
|
|
Packit Service |
4684c1 |
if (err < 0)
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (FD_ISSET(hd->fd, &rset))
|
|
Packit Service |
4684c1 |
return IN_NET;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef _WIN32
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int state;
|
|
Packit Service |
4684c1 |
state =
|
|
Packit Service |
4684c1 |
WaitForSingleObject(GetStdHandle
|
|
Packit Service |
4684c1 |
(STD_INPUT_HANDLE), 200);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (state == WAIT_OBJECT_0)
|
|
Packit Service |
4684c1 |
return IN_KEYBOARD;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#else
|
|
Packit Service |
4684c1 |
if (!user_term && FD_ISSET(fileno(stdin), &rset))
|
|
Packit Service |
4684c1 |
return IN_KEYBOARD;
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
if (err == 0 && user_term)
|
|
Packit Service |
4684c1 |
return IN_TERM;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
while (err == 0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return IN_NONE;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int try_rehandshake(socket_st * hd)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = do_handshake(hd);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "*** ReHandshake has failed\n");
|
|
Packit Service |
4684c1 |
gnutls_perror(ret);
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
log_msg(stdout, "- ReHandshake was completed\n");
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int try_rekey(socket_st * hd, unsigned peer)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = gnutls_session_key_update(hd->session, peer?GNUTLS_KU_PEER:0);
|
|
Packit Service |
4684c1 |
} while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "*** Rekey has failed: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
log_msg(stdout, "- Rekey was completed\n");
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int try_resume(socket_st * hd)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret, socket_flags = SOCKET_FLAG_DONT_PRINT_ERRORS;
|
|
Packit Service |
4684c1 |
gnutls_datum_t rdata = {NULL, 0};
|
|
Packit Service |
4684c1 |
gnutls_datum_t edata = {NULL, 0};
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_session_is_resumed(hd->session) == 0) {
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
/* not resumed - obtain the session data */
|
|
Packit Service |
4684c1 |
ret = gnutls_session_get_data2(hd->session, &rdata);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
rdata.data = NULL;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((gnutls_protocol_get_version(hd->session) != GNUTLS_TLS1_3) ||
|
|
Packit Service |
4684c1 |
((gnutls_session_get_flags(hd->session) &
|
|
Packit Service |
4684c1 |
GNUTLS_SFLAGS_SESSION_TICKET))) {
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} while (waitresumption);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
/* resumed - try to reuse the previous session data */
|
|
Packit Service |
4684c1 |
rdata.data = hd->rdata.data;
|
|
Packit Service |
4684c1 |
rdata.size = hd->rdata.size;
|
|
Packit Service |
4684c1 |
hd->rdata.data = NULL;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
log_msg(stdout, "- Disconnecting\n");
|
|
Packit Service |
4684c1 |
socket_bye(hd, 1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
canonicalize_host(hostname, service, sizeof(service));
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
log_msg
|
|
Packit Service |
4684c1 |
(stdout, "\n\n- Connecting again- trying to resume previous session\n");
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(STARTTLS_PROTO))
|
|
Packit Service |
4684c1 |
socket_flags |= SOCKET_FLAG_STARTTLS;
|
|
Packit Service |
4684c1 |
else if (fastopen)
|
|
Packit Service |
4684c1 |
socket_flags |= SOCKET_FLAG_FASTOPEN;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (udp)
|
|
Packit Service |
4684c1 |
socket_flags |= SOCKET_FLAG_UDP;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(EARLYDATA)) {
|
|
Packit Service |
4684c1 |
FILE *fp;
|
|
Packit Service |
4684c1 |
size_t size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
fp = fopen(OPT_ARG(EARLYDATA), "r");
|
|
Packit Service |
4684c1 |
if (fp == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "could not open %s\n", OPT_ARG(EARLYDATA));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
edata.data = (void *) fread_file(fp, 0, &size);
|
|
Packit Service |
4684c1 |
edata.size = size;
|
|
Packit Service |
4684c1 |
fclose(fp);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
socket_open3(hd, hostname, service, OPT_ARG(STARTTLS_PROTO),
|
|
Packit Service |
4684c1 |
socket_flags, CONNECT_MSG, &rdata, &edata);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
log_msg(stdout, "- Resume Handshake was completed\n");
|
|
Packit Service |
4684c1 |
if (gnutls_session_is_resumed(hd->session) != 0)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "*** This is a resumed session\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static
|
|
Packit Service |
4684c1 |
bool parse_for_inline_commands_in_buffer(char *buffer, size_t bytes,
|
|
Packit Service |
4684c1 |
inline_cmds_st * inline_cmds)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
ssize_t local_bytes, match_bytes, prev_bytes_copied, ii;
|
|
Packit Service |
4684c1 |
unsigned jj;
|
|
Packit Service |
4684c1 |
char *local_buffer_ptr, *ptr;
|
|
Packit Service |
4684c1 |
char inline_command_string[MAX_INLINE_COMMAND_BYTES];
|
|
Packit Service |
4684c1 |
ssize_t l;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
inline_cmds->bytes_to_flush = 0;
|
|
Packit Service |
4684c1 |
inline_cmds->cmd_found = INLINE_COMMAND_NONE;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (inline_cmds->bytes_copied) {
|
|
Packit Service |
4684c1 |
local_buffer_ptr =
|
|
Packit Service |
4684c1 |
&inline_cmds->inline_cmd_buffer[inline_cmds->
|
|
Packit Service |
4684c1 |
bytes_copied];
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
local_bytes =
|
|
Packit Service |
4684c1 |
((inline_cmds->bytes_copied + bytes) <=
|
|
Packit Service |
4684c1 |
MAX_INLINE_COMMAND_BYTES) ? (ssize_t) bytes
|
|
Packit Service |
4684c1 |
: (MAX_INLINE_COMMAND_BYTES -
|
|
Packit Service |
4684c1 |
inline_cmds->bytes_copied);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
memcpy(local_buffer_ptr, buffer, local_bytes);
|
|
Packit Service |
4684c1 |
prev_bytes_copied = inline_cmds->bytes_copied;
|
|
Packit Service |
4684c1 |
inline_cmds->new_buffer_ptr = buffer + local_bytes;
|
|
Packit Service |
4684c1 |
inline_cmds->bytes_copied += local_bytes;
|
|
Packit Service |
4684c1 |
local_buffer_ptr = inline_cmds->inline_cmd_buffer;
|
|
Packit Service |
4684c1 |
local_bytes = inline_cmds->bytes_copied;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
prev_bytes_copied = 0;
|
|
Packit Service |
4684c1 |
local_buffer_ptr = buffer;
|
|
Packit Service |
4684c1 |
local_bytes = bytes;
|
|
Packit Service |
4684c1 |
inline_cmds->new_buffer_ptr = buffer + bytes;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
assert(local_buffer_ptr != NULL);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
inline_cmds->current_ptr = local_buffer_ptr;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (local_buffer_ptr[0] == inline_commands_prefix[0]
|
|
Packit Service |
4684c1 |
&& inline_cmds->lf_found) {
|
|
Packit Service |
4684c1 |
for (jj = 0; jj < NUM_INLINE_COMMANDS; jj++) {
|
|
Packit Service |
4684c1 |
if (inline_commands_prefix[0] != '^') { /* refer inline_cmds.h for usage of ^ */
|
|
Packit Service |
4684c1 |
strcpy(inline_command_string,
|
|
Packit Service |
4684c1 |
inline_commands_def[jj].string);
|
|
Packit Service |
4684c1 |
inline_command_string[strlen
|
|
Packit Service |
4684c1 |
(inline_commands_def
|
|
Packit Service |
4684c1 |
[jj].string)] =
|
|
Packit Service |
4684c1 |
'\0';
|
|
Packit Service |
4684c1 |
inline_command_string[0] =
|
|
Packit Service |
4684c1 |
inline_commands_prefix[0];
|
|
Packit Service |
4684c1 |
/* Inline commands are delimited by the inline_commands_prefix[0] (default is ^).
|
|
Packit Service |
4684c1 |
The inline_commands_def[].string includes a trailing LF */
|
|
Packit Service |
4684c1 |
inline_command_string[strlen
|
|
Packit Service |
4684c1 |
(inline_commands_def
|
|
Packit Service |
4684c1 |
[jj].string) - 2] =
|
|
Packit Service |
4684c1 |
inline_commands_prefix[0];
|
|
Packit Service |
4684c1 |
ptr = inline_command_string;
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
ptr = inline_commands_def[jj].string;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
l = strlen(ptr);
|
|
Packit Service |
4684c1 |
match_bytes = (local_bytes <= l) ? local_bytes : l;
|
|
Packit Service |
4684c1 |
if (strncmp(ptr, local_buffer_ptr, match_bytes) ==
|
|
Packit Service |
4684c1 |
0) {
|
|
Packit Service |
4684c1 |
if (match_bytes == (ssize_t) strlen(ptr)) {
|
|
Packit Service |
4684c1 |
inline_cmds->new_buffer_ptr =
|
|
Packit Service |
4684c1 |
buffer + match_bytes -
|
|
Packit Service |
4684c1 |
prev_bytes_copied;
|
|
Packit Service |
4684c1 |
inline_cmds->cmd_found =
|
|
Packit Service |
4684c1 |
inline_commands_def[jj].
|
|
Packit Service |
4684c1 |
command;
|
|
Packit Service |
4684c1 |
inline_cmds->bytes_copied = 0; /* reset it */
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
/* partial command */
|
|
Packit Service |
4684c1 |
memcpy(&inline_cmds->
|
|
Packit Service |
4684c1 |
inline_cmd_buffer
|
|
Packit Service |
4684c1 |
[inline_cmds->bytes_copied],
|
|
Packit Service |
4684c1 |
buffer, bytes);
|
|
Packit Service |
4684c1 |
inline_cmds->bytes_copied += bytes;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
return true;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
/* else - if not a match, do nothing here */
|
|
Packit Service |
4684c1 |
} /* for */
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (ii = prev_bytes_copied; ii < local_bytes; ii++) {
|
|
Packit Service |
4684c1 |
if (ii && local_buffer_ptr[ii] == inline_commands_prefix[0]
|
|
Packit Service |
4684c1 |
&& inline_cmds->lf_found) {
|
|
Packit Service |
4684c1 |
/* possible inline command. First, let's flush bytes up to ^ */
|
|
Packit Service |
4684c1 |
inline_cmds->new_buffer_ptr =
|
|
Packit Service |
4684c1 |
buffer + ii - prev_bytes_copied;
|
|
Packit Service |
4684c1 |
inline_cmds->bytes_to_flush = ii;
|
|
Packit Service |
4684c1 |
inline_cmds->lf_found = true;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* bytes to flush starts at inline_cmds->current_ptr */
|
|
Packit Service |
4684c1 |
return true;
|
|
Packit Service |
4684c1 |
} else if (local_buffer_ptr[ii] == '\n') {
|
|
Packit Service |
4684c1 |
inline_cmds->lf_found = true;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
inline_cmds->lf_found = false;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} /* for */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
inline_cmds->bytes_copied = 0; /* reset it */
|
|
Packit Service |
4684c1 |
return false; /* not an inline command */
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static
|
|
Packit Service |
4684c1 |
int run_inline_command(inline_cmds_st * cmd, socket_st * hd)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
switch (cmd->cmd_found) {
|
|
Packit Service |
4684c1 |
case INLINE_COMMAND_RESUME:
|
|
Packit Service |
4684c1 |
return try_resume(hd);
|
|
Packit Service |
4684c1 |
case INLINE_COMMAND_REKEY_LOCAL:
|
|
Packit Service |
4684c1 |
return try_rekey(hd, 0);
|
|
Packit Service |
4684c1 |
case INLINE_COMMAND_REKEY_BOTH:
|
|
Packit Service |
4684c1 |
return try_rekey(hd, 1);
|
|
Packit Service |
4684c1 |
case INLINE_COMMAND_RENEGOTIATE:
|
|
Packit Service |
4684c1 |
return try_rehandshake(hd);
|
|
Packit Service |
4684c1 |
default:
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static
|
|
Packit Service |
4684c1 |
int do_inline_command_processing(char *buffer_ptr, size_t curr_bytes,
|
|
Packit Service |
4684c1 |
socket_st * hd,
|
|
Packit Service |
4684c1 |
inline_cmds_st * inline_cmds)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int skip_bytes, bytes;
|
|
Packit Service |
4684c1 |
bool inline_cmd_start_found;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
bytes = curr_bytes;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
continue_inline_processing:
|
|
Packit Service |
4684c1 |
/* parse_for_inline_commands_in_buffer hunts for start of an inline command
|
|
Packit Service |
4684c1 |
* sequence. The function maintains state information in inline_cmds.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
inline_cmd_start_found =
|
|
Packit Service |
4684c1 |
parse_for_inline_commands_in_buffer(buffer_ptr, bytes,
|
|
Packit Service |
4684c1 |
inline_cmds);
|
|
Packit Service |
4684c1 |
if (!inline_cmd_start_found)
|
|
Packit Service |
4684c1 |
return bytes;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* inline_cmd_start_found is set */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (inline_cmds->bytes_to_flush) {
|
|
Packit Service |
4684c1 |
/* start of an inline command sequence found, but is not
|
|
Packit Service |
4684c1 |
* at the beginning of buffer. So, we flush all preceding bytes.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
return inline_cmds->bytes_to_flush;
|
|
Packit Service |
4684c1 |
} else if (inline_cmds->cmd_found == INLINE_COMMAND_NONE) {
|
|
Packit Service |
4684c1 |
/* partial command found */
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
/* complete inline command found and is at the start */
|
|
Packit Service |
4684c1 |
if (run_inline_command(inline_cmds, hd))
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
inline_cmds->cmd_found = INLINE_COMMAND_NONE;
|
|
Packit Service |
4684c1 |
skip_bytes = inline_cmds->new_buffer_ptr - buffer_ptr;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (skip_bytes >= bytes)
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
else {
|
|
Packit Service |
4684c1 |
buffer_ptr = inline_cmds->new_buffer_ptr;
|
|
Packit Service |
4684c1 |
bytes -= skip_bytes;
|
|
Packit Service |
4684c1 |
goto continue_inline_processing;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void
|
|
Packit Service |
4684c1 |
print_other_info(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_OCSP
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
unsigned i;
|
|
Packit Service |
4684c1 |
unsigned int list_size;
|
|
Packit Service |
4684c1 |
gnutls_datum_t oresp;
|
|
Packit Service |
4684c1 |
const gnutls_datum_t * peers;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
peers = gnutls_certificate_get_peers(session, &list_size);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!ENABLED_OPT(VERBOSE) || peers == NULL)
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i = 0; i < list_size; i++) {
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_status_request_get2(session, i, &oresp);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
oresp.data = NULL;
|
|
Packit Service |
4684c1 |
oresp.size = 0;
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_ocsp_resp_t r;
|
|
Packit Service |
4684c1 |
gnutls_datum_t p;
|
|
Packit Service |
4684c1 |
unsigned flag;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_init(&r);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "ocsp_resp_init: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_import(r, &oresp);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "importing response: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (print_cert != 0)
|
|
Packit Service |
4684c1 |
flag = GNUTLS_OCSP_PRINT_FULL;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
flag = GNUTLS_OCSP_PRINT_COMPACT;
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_ocsp_resp_print(r, flag, &p);
|
|
Packit Service |
4684c1 |
gnutls_ocsp_resp_deinit(r);
|
|
Packit Service |
4684c1 |
if (ret>=0) {
|
|
Packit Service |
4684c1 |
log_msg(stdout, "%s", (char*) p.data);
|
|
Packit Service |
4684c1 |
gnutls_free(p.data);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int main(int argc, char **argv)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
int ii, inp;
|
|
Packit Service |
4684c1 |
char buffer[MAX_BUF + 1];
|
|
Packit Service |
4684c1 |
int user_term = 0, retval = 0;
|
|
Packit Service |
4684c1 |
socket_st hd;
|
|
Packit Service |
4684c1 |
ssize_t bytes, keyboard_bytes;
|
|
Packit Service |
4684c1 |
char *keyboard_buffer_ptr;
|
|
Packit Service |
4684c1 |
inline_cmds_st inline_cmds;
|
|
Packit Service |
4684c1 |
int socket_flags = SOCKET_FLAG_DONT_PRINT_ERRORS;
|
|
Packit Service |
4684c1 |
FILE *server_fp = NULL;
|
|
Packit Service |
4684c1 |
FILE *client_fp = NULL;
|
|
Packit Service |
4684c1 |
FILE *logfile = NULL;
|
|
Packit Service |
4684c1 |
#ifndef _WIN32
|
|
Packit Service |
4684c1 |
struct sigaction new_action;
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cmd_parser(argc, argv);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(LOGFILE)) {
|
|
Packit Service |
4684c1 |
logfile = fopen(OPT_ARG(LOGFILE), "w+");
|
|
Packit Service |
4684c1 |
if (!logfile) {
|
|
Packit Service |
4684c1 |
log_msg(stderr, "Unable to open '%s'!\n", OPT_ARG(LOGFILE));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
log_set(logfile);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_global_set_log_function(tls_log_func);
|
|
Packit Service |
4684c1 |
gnutls_global_set_log_level(OPT_VALUE_DEBUG);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((ret = gnutls_global_init()) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "global_init: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (hostname == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "No hostname given\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
sockets_init();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
init_global_tls_stuff();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
canonicalize_host(hostname, service, sizeof(service));
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (udp)
|
|
Packit Service |
4684c1 |
socket_flags |= SOCKET_FLAG_UDP;
|
|
Packit Service |
4684c1 |
if (fastopen)
|
|
Packit Service |
4684c1 |
socket_flags |= SOCKET_FLAG_FASTOPEN;
|
|
Packit Service |
4684c1 |
if (verbose)
|
|
Packit Service |
4684c1 |
socket_flags |= SOCKET_FLAG_VERBOSE;
|
|
Packit Service |
4684c1 |
if (starttls)
|
|
Packit Service |
4684c1 |
socket_flags |= SOCKET_FLAG_RAW;
|
|
Packit Service |
4684c1 |
else if (HAVE_OPT(STARTTLS_PROTO))
|
|
Packit Service |
4684c1 |
socket_flags |= SOCKET_FLAG_STARTTLS;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SAVE_SERVER_TRACE)) {
|
|
Packit Service |
4684c1 |
server_fp = fopen(OPT_ARG(SAVE_SERVER_TRACE), "wb");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SAVE_CLIENT_TRACE)) {
|
|
Packit Service |
4684c1 |
client_fp = fopen(OPT_ARG(SAVE_CLIENT_TRACE), "wb");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
socket_open2(&hd, hostname, service, OPT_ARG(STARTTLS_PROTO),
|
|
Packit Service |
4684c1 |
socket_flags, CONNECT_MSG, NULL, NULL,
|
|
Packit Service |
4684c1 |
server_fp, client_fp);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hd.verbose = verbose;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (hd.secure) {
|
|
Packit Service |
4684c1 |
log_msg(stdout, "- Handshake was completed\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (resume != 0)
|
|
Packit Service |
4684c1 |
if (try_resume(&hd)) {
|
|
Packit Service |
4684c1 |
retval = 1;
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
print_other_info(hd.session);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Warning! Do not touch this text string, it is used by external
|
|
Packit Service |
4684c1 |
programs to search for when gnutls-cli has reached this point. */
|
|
Packit Service |
4684c1 |
log_msg(stdout, "\n- Simple Client Mode:\n\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (rehandshake)
|
|
Packit Service |
4684c1 |
if (try_rehandshake(&hd)) {
|
|
Packit Service |
4684c1 |
retval = 1;
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifndef _WIN32
|
|
Packit Service |
4684c1 |
new_action.sa_handler = starttls_alarm;
|
|
Packit Service |
4684c1 |
sigemptyset(&new_action.sa_mask);
|
|
Packit Service |
4684c1 |
new_action.sa_flags = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
sigaction(SIGALRM, &new_action, NULL);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
fflush(stdout);
|
|
Packit Service |
4684c1 |
fflush(stderr);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* do not buffer */
|
|
Packit Service |
4684c1 |
#ifndef _WIN32
|
|
Packit Service |
4684c1 |
setbuf(stdin, NULL);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
setbuf(stdout, NULL);
|
|
Packit Service |
4684c1 |
setbuf(stderr, NULL);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
memset(&inline_cmds, 0, sizeof(inline_cmds_st));
|
|
Packit Service |
4684c1 |
if (inline_commands) {
|
|
Packit Service |
4684c1 |
inline_cmds.lf_found = true; /* initially, at start of line */
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (;;) {
|
|
Packit Service |
4684c1 |
if (starttls_alarmed && !hd.secure) {
|
|
Packit Service |
4684c1 |
/* Warning! Do not touch this text string, it is used by
|
|
Packit Service |
4684c1 |
external programs to search for when gnutls-cli has
|
|
Packit Service |
4684c1 |
reached this point. */
|
|
Packit Service |
4684c1 |
fprintf(stderr, "*** Starting TLS handshake\n");
|
|
Packit Service |
4684c1 |
ret = do_handshake(&hd;;
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Handshake has failed\n");
|
|
Packit Service |
4684c1 |
retval = 1;
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
inp = check_net_or_keyboard_input(&hd, user_term);
|
|
Packit Service |
4684c1 |
if (inp == IN_TERM)
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (inp == IN_NET) {
|
|
Packit Service |
4684c1 |
memset(buffer, 0, MAX_BUF + 1);
|
|
Packit Service |
4684c1 |
ret = socket_recv(&hd, buffer, MAX_BUF);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret == 0 || (ret == GNUTLS_E_PREMATURE_TERMINATION && user_term)) {
|
|
Packit Service |
4684c1 |
log_msg
|
|
Packit Service |
4684c1 |
(stdout, "- Peer has closed the GnuTLS connection\n");
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
} else if (handle_error(&hd, ret) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Server has terminated the connection abnormally.\n");
|
|
Packit Service |
4684c1 |
retval = 1;
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
} else if (ret > 0) {
|
|
Packit Service |
4684c1 |
if (verbose != 0)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "- Received[%d]: ", ret);
|
|
Packit Service |
4684c1 |
for (ii = 0; ii < ret; ii++) {
|
|
Packit Service |
4684c1 |
fputc(buffer[ii], stdout);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
fflush(stdout);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (inp == IN_KEYBOARD && user_term == 0) {
|
|
Packit Service |
4684c1 |
if ((bytes =
|
|
Packit Service |
4684c1 |
read(fileno(stdin), buffer,
|
|
Packit Service |
4684c1 |
MAX_BUF - 1)) <= 0) {
|
|
Packit Service |
4684c1 |
if (hd.secure == 0) {
|
|
Packit Service |
4684c1 |
/* Warning! Do not touch this text string, it is
|
|
Packit Service |
4684c1 |
used by external programs to search for when
|
|
Packit Service |
4684c1 |
gnutls-cli has reached this point. */
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Starting TLS handshake\n");
|
|
Packit Service |
4684c1 |
ret = do_handshake(&hd;;
|
|
Packit Service |
4684c1 |
clearerr(stdin);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Handshake has failed\n");
|
|
Packit Service |
4684c1 |
retval = 1;
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = gnutls_bye(hd.session, GNUTLS_SHUT_WR);
|
|
Packit Service |
4684c1 |
} while (ret == GNUTLS_E_INTERRUPTED ||
|
|
Packit Service |
4684c1 |
ret == GNUTLS_E_AGAIN);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
user_term = 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
buffer[bytes] = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (crlf != 0) {
|
|
Packit Service |
4684c1 |
char *b = strchr(buffer, '\n');
|
|
Packit Service |
4684c1 |
if (b != NULL) {
|
|
Packit Service |
4684c1 |
strcpy(b, "\r\n");
|
|
Packit Service |
4684c1 |
bytes++;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
keyboard_bytes = bytes;
|
|
Packit Service |
4684c1 |
keyboard_buffer_ptr = buffer;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
inline_command_processing:
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (inline_commands) {
|
|
Packit Service |
4684c1 |
keyboard_bytes =
|
|
Packit Service |
4684c1 |
do_inline_command_processing
|
|
Packit Service |
4684c1 |
(keyboard_buffer_ptr, keyboard_bytes,
|
|
Packit Service |
4684c1 |
&hd, &inline_cmds);
|
|
Packit Service |
4684c1 |
if (keyboard_bytes == 0)
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
else if (keyboard_bytes < 0) { /* error processing an inline command */
|
|
Packit Service |
4684c1 |
retval = 1;
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
/* current_ptr could point to either an inline_cmd_buffer
|
|
Packit Service |
4684c1 |
* or may point to start or an offset into buffer.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
keyboard_buffer_ptr =
|
|
Packit Service |
4684c1 |
inline_cmds.current_ptr;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ranges
|
|
Packit Service |
4684c1 |
&& gnutls_record_can_use_length_hiding(hd.
|
|
Packit Service |
4684c1 |
session))
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_range_st range;
|
|
Packit Service |
4684c1 |
range.low = 0;
|
|
Packit Service |
4684c1 |
range.high = MAX_BUF;
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
socket_send_range(&hd,
|
|
Packit Service |
4684c1 |
keyboard_buffer_ptr,
|
|
Packit Service |
4684c1 |
keyboard_bytes,
|
|
Packit Service |
4684c1 |
&range);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
socket_send(&hd, keyboard_buffer_ptr,
|
|
Packit Service |
4684c1 |
keyboard_bytes);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret > 0) {
|
|
Packit Service |
4684c1 |
if (verbose != 0)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "- Sent: %d bytes\n", ret);
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
handle_error(&hd, ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (inline_commands &&
|
|
Packit Service |
4684c1 |
inline_cmds.new_buffer_ptr < (buffer + bytes))
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
keyboard_buffer_ptr =
|
|
Packit Service |
4684c1 |
inline_cmds.new_buffer_ptr;
|
|
Packit Service |
4684c1 |
keyboard_bytes =
|
|
Packit Service |
4684c1 |
(buffer + bytes) - keyboard_buffer_ptr;
|
|
Packit Service |
4684c1 |
goto inline_command_processing;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cleanup:
|
|
Packit Service |
4684c1 |
socket_bye(&hd, 0);
|
|
Packit Service |
4684c1 |
if (logfile) {
|
|
Packit Service |
4684c1 |
fclose(logfile);
|
|
Packit Service |
4684c1 |
logfile = NULL;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_SRP
|
|
Packit Service |
4684c1 |
if (srp_cred)
|
|
Packit Service |
4684c1 |
gnutls_srp_free_client_credentials(srp_cred);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_PSK
|
|
Packit Service |
4684c1 |
if (psk_cred)
|
|
Packit Service |
4684c1 |
gnutls_psk_free_client_credentials(psk_cred);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_certificate_free_credentials(xcred);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_ANON
|
|
Packit Service |
4684c1 |
gnutls_anon_free_client_credentials(anon_cred);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_global_deinit();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return retval;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static
|
|
Packit Service |
4684c1 |
void print_priority_list(void)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
unsigned int idx;
|
|
Packit Service |
4684c1 |
const char *str;
|
|
Packit Service |
4684c1 |
unsigned int lineb = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Priority strings in GnuTLS %s:\n", gnutls_check_version(NULL));
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
fputs("\t", stdout);
|
|
Packit Service |
4684c1 |
for (idx=0;;idx++) {
|
|
Packit Service |
4684c1 |
str = gnutls_priority_string_list(idx, GNUTLS_PRIORITY_LIST_INIT_KEYWORDS);
|
|
Packit Service |
4684c1 |
if (str == NULL)
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
lineb += log_msg(stdout, "%s ", str);
|
|
Packit Service |
4684c1 |
if (lineb > 64) {
|
|
Packit Service |
4684c1 |
lineb = 0;
|
|
Packit Service |
4684c1 |
log_msg(stdout, "\n\t");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
log_msg(stdout, "\n\nSpecial strings:\n");
|
|
Packit Service |
4684c1 |
lineb = 0;
|
|
Packit Service |
4684c1 |
fputs("\t", stdout);
|
|
Packit Service |
4684c1 |
for (idx=0;;idx++) {
|
|
Packit Service |
4684c1 |
str = gnutls_priority_string_list(idx, GNUTLS_PRIORITY_LIST_SPECIAL);
|
|
Packit Service |
4684c1 |
if (str == NULL)
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
if (str[0] == 0)
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
lineb += log_msg(stdout, "%%%s ", str);
|
|
Packit Service |
4684c1 |
if (lineb > 64) {
|
|
Packit Service |
4684c1 |
lineb = 0;
|
|
Packit Service |
4684c1 |
log_msg(stdout, "\n\t");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
log_msg(stdout, "\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void cmd_parser(int argc, char **argv)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
char *rest = NULL;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int optct = optionProcess(&gnutls_cliOptions, argc, argv);
|
|
Packit Service |
4684c1 |
argc -= optct;
|
|
Packit Service |
4684c1 |
argv += optct;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (rest == NULL && argc > 0)
|
|
Packit Service |
4684c1 |
rest = argv[0];
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(FIPS140_MODE)) {
|
|
Packit Service |
4684c1 |
if (gnutls_fips140_mode_enabled() != 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "library is in FIPS140-2 mode\n");
|
|
Packit Service |
4684c1 |
exit(0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
fprintf(stderr, "library is NOT in FIPS140-2 mode\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(BENCHMARK_CIPHERS)) {
|
|
Packit Service |
4684c1 |
benchmark_cipher(OPT_VALUE_DEBUG);
|
|
Packit Service |
4684c1 |
exit(0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(BENCHMARK_TLS_CIPHERS)) {
|
|
Packit Service |
4684c1 |
benchmark_tls(OPT_VALUE_DEBUG, 1);
|
|
Packit Service |
4684c1 |
exit(0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(BENCHMARK_TLS_KX)) {
|
|
Packit Service |
4684c1 |
benchmark_tls(OPT_VALUE_DEBUG, 0);
|
|
Packit Service |
4684c1 |
exit(0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PRIORITY)) {
|
|
Packit Service |
4684c1 |
priorities = OPT_ARG(PRIORITY);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
verbose = HAVE_OPT(VERBOSE);
|
|
Packit Service |
4684c1 |
if (verbose)
|
|
Packit Service |
4684c1 |
print_cert = 1;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
print_cert = HAVE_OPT(PRINT_CERT);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(LIST)) {
|
|
Packit Service |
4684c1 |
print_list(priorities, verbose);
|
|
Packit Service |
4684c1 |
exit(0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PRIORITY_LIST)) {
|
|
Packit Service |
4684c1 |
print_priority_list();
|
|
Packit Service |
4684c1 |
exit(0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
disable_sni = HAVE_OPT(DISABLE_SNI);
|
|
Packit Service |
4684c1 |
disable_extensions = HAVE_OPT(DISABLE_EXTENSIONS);
|
|
Packit Service |
4684c1 |
if (disable_extensions)
|
|
Packit Service |
4684c1 |
init_flags |= GNUTLS_NO_EXTENSIONS;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SINGLE_KEY_SHARE))
|
|
Packit Service |
4684c1 |
init_flags |= GNUTLS_KEY_SHARE_TOP;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(POST_HANDSHAKE_AUTH))
|
|
Packit Service |
4684c1 |
init_flags |= GNUTLS_POST_HANDSHAKE_AUTH;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
inline_commands = HAVE_OPT(INLINE_COMMANDS);
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(INLINE_COMMANDS_PREFIX)) {
|
|
Packit Service |
4684c1 |
if (strlen(OPT_ARG(INLINE_COMMANDS_PREFIX)) > 1) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"inline-commands-prefix value is a single US-ASCII character (octets 0 - 127)\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
inline_commands_prefix =
|
|
Packit Service |
4684c1 |
(char *) OPT_ARG(INLINE_COMMANDS_PREFIX);
|
|
Packit Service |
4684c1 |
if (!isascii(inline_commands_prefix[0])) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"inline-commands-prefix value is a single US-ASCII character (octets 0 - 127)\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
inline_commands_prefix = "^";
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
starttls = HAVE_OPT(STARTTLS);
|
|
Packit Service |
4684c1 |
resume = HAVE_OPT(RESUME);
|
|
Packit Service |
4684c1 |
rehandshake = HAVE_OPT(REHANDSHAKE);
|
|
Packit Service |
4684c1 |
insecure = HAVE_OPT(INSECURE);
|
|
Packit Service |
4684c1 |
ranges = HAVE_OPT(RANGES);
|
|
Packit Service |
4684c1 |
waitresumption = HAVE_OPT(WAITRESUMPTION);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (insecure || HAVE_OPT(VERIFY_ALLOW_BROKEN)) {
|
|
Packit Service |
4684c1 |
global_vflags |= GNUTLS_VERIFY_ALLOW_BROKEN;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
udp = HAVE_OPT(UDP);
|
|
Packit Service |
4684c1 |
mtu = OPT_VALUE_MTU;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PORT)) {
|
|
Packit Service |
4684c1 |
snprintf(service, sizeof(service), "%s", OPT_ARG(PORT));
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(STARTTLS_PROTO))
|
|
Packit Service |
4684c1 |
snprintf(service, sizeof(service), "%s", starttls_proto_to_service(OPT_ARG(STARTTLS_PROTO)));
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
strcpy(service, "443");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
record_max_size = OPT_VALUE_RECORDSIZE;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(X509FMTDER))
|
|
Packit Service |
4684c1 |
x509ctype = GNUTLS_X509_FMT_DER;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
x509ctype = GNUTLS_X509_FMT_PEM;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SRPUSERNAME))
|
|
Packit Service |
4684c1 |
srp_username = OPT_ARG(SRPUSERNAME);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SRPPASSWD))
|
|
Packit Service |
4684c1 |
srp_passwd = OPT_ARG(SRPPASSWD);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(X509CAFILE))
|
|
Packit Service |
4684c1 |
x509_cafile = OPT_ARG(X509CAFILE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(X509CRLFILE))
|
|
Packit Service |
4684c1 |
x509_crlfile = OPT_ARG(X509CRLFILE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(X509KEYFILE))
|
|
Packit Service |
4684c1 |
x509_keyfile = OPT_ARG(X509KEYFILE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(X509CERTFILE))
|
|
Packit Service |
4684c1 |
x509_certfile = OPT_ARG(X509CERTFILE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(RAWPKKEYFILE))
|
|
Packit Service |
4684c1 |
rawpk_keyfile = OPT_ARG(RAWPKKEYFILE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(RAWPKFILE))
|
|
Packit Service |
4684c1 |
rawpk_file = OPT_ARG(RAWPKFILE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PSKUSERNAME))
|
|
Packit Service |
4684c1 |
psk_username = OPT_ARG(PSKUSERNAME);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PSKKEY)) {
|
|
Packit Service |
4684c1 |
psk_key.data = (unsigned char *) OPT_ARG(PSKKEY);
|
|
Packit Service |
4684c1 |
psk_key.size = strlen(OPT_ARG(PSKKEY));
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
psk_key.size = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
crlf = HAVE_OPT(CRLF);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef TCP_FASTOPEN
|
|
Packit Service |
4684c1 |
fastopen = HAVE_OPT(FASTOPEN);
|
|
Packit Service |
4684c1 |
#else
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(FASTOPEN)) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Warning: TCP Fast Open not supported on this OS\n");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (rest != NULL)
|
|
Packit Service |
4684c1 |
hostname = rest;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (hostname == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "No hostname specified\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void check_server_cmd(socket_st * socket, int ret)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
if (socket->secure) {
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_REHANDSHAKE) {
|
|
Packit Service |
4684c1 |
/* There is a race condition here. If application
|
|
Packit Service |
4684c1 |
* data is sent after the rehandshake request,
|
|
Packit Service |
4684c1 |
* the server thinks we ignored his request.
|
|
Packit Service |
4684c1 |
* This is a bad design of this client.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
log_msg(stdout, "*** Received rehandshake request\n");
|
|
Packit Service |
4684c1 |
/* gnutls_alert_send( session, GNUTLS_AL_WARNING, GNUTLS_A_NO_RENEGOTIATION); */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = do_handshake(socket);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret == 0) {
|
|
Packit Service |
4684c1 |
log_msg(stdout, "*** Rehandshake was performed.\n");
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
log_msg(stdout, "*** Rehandshake Failed: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else if (ret == GNUTLS_E_REAUTH_REQUEST) {
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = gnutls_reauth(socket->session, 0);
|
|
Packit Service |
4684c1 |
} while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret == 0) {
|
|
Packit Service |
4684c1 |
log_msg(stdout, "*** Re-auth was performed.\n");
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
log_msg(stdout, "*** Re-auth failed: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int do_handshake(socket_st * socket)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (fastopen && socket->connect_addrlen) {
|
|
Packit Service |
4684c1 |
gnutls_transport_set_fastopen(socket->session, socket->fd,
|
|
Packit Service |
4684c1 |
(struct sockaddr*)&socket->connect_addr,
|
|
Packit Service |
4684c1 |
socket->connect_addrlen, 0);
|
|
Packit Service |
4684c1 |
socket->connect_addrlen = 0;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
set_read_funcs(socket->session);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
gnutls_handshake_set_timeout(socket->session,
|
|
Packit Service |
4684c1 |
GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
|
|
Packit Service |
4684c1 |
ret = gnutls_handshake(socket->session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
handle_error(socket, ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret == 0) {
|
|
Packit Service |
4684c1 |
/* print some information */
|
|
Packit Service |
4684c1 |
print_info(socket->session, verbose, HAVE_OPT(X509CERTFILE)?P_WAIT_FOR_CERT:0);
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(KEYMATEXPORT))
|
|
Packit Service |
4684c1 |
print_key_material(socket->session,
|
|
Packit Service |
4684c1 |
OPT_ARG(KEYMATEXPORT),
|
|
Packit Service |
4684c1 |
HAVE_OPT(KEYMATEXPORTSIZE) ?
|
|
Packit Service |
4684c1 |
OPT_VALUE_KEYMATEXPORTSIZE : 20);
|
|
Packit Service |
4684c1 |
socket->secure = 1;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
gnutls_alert_send_appropriate(socket->session, ret);
|
|
Packit Service |
4684c1 |
shutdown(socket->fd, SHUT_RDWR);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int
|
|
Packit Service |
4684c1 |
srp_username_callback(gnutls_session_t session,
|
|
Packit Service |
4684c1 |
char **username, char **password)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
if (srp_username == NULL || srp_passwd == NULL) {
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*username = gnutls_strdup(srp_username);
|
|
Packit Service |
4684c1 |
*password = gnutls_strdup(srp_passwd);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int
|
|
Packit Service |
4684c1 |
psk_callback(gnutls_session_t session, char **username,
|
|
Packit Service |
4684c1 |
gnutls_datum_t * key)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
const char *hint = gnutls_psk_client_get_hint(session);
|
|
Packit Service |
4684c1 |
char *rawkey;
|
|
Packit Service |
4684c1 |
char *passwd;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
size_t res_size;
|
|
Packit Service |
4684c1 |
gnutls_datum_t tmp;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
log_msg(stdout, "- PSK client callback. ");
|
|
Packit Service |
4684c1 |
if (hint)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "PSK hint '%s'\n", hint);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
log_msg(stdout, "No PSK hint\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PSKUSERNAME))
|
|
Packit Service |
4684c1 |
*username = gnutls_strdup(OPT_ARG(PSKUSERNAME));
|
|
Packit Service |
4684c1 |
else {
|
|
Packit Service |
4684c1 |
char *p = NULL;
|
|
Packit Service |
4684c1 |
size_t n;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Enter PSK identity: ");
|
|
Packit Service |
4684c1 |
fflush(stdout);
|
|
Packit Service |
4684c1 |
ret = getline(&p, &n, stdin);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret == -1 || p == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"No username given, aborting...\n");
|
|
Packit Service |
4684c1 |
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (p[strlen(p) - 1] == '\n')
|
|
Packit Service |
4684c1 |
p[strlen(p) - 1] = '\0';
|
|
Packit Service |
4684c1 |
if (p[strlen(p) - 1] == '\r')
|
|
Packit Service |
4684c1 |
p[strlen(p) - 1] = '\0';
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*username = gnutls_strdup(p);
|
|
Packit Service |
4684c1 |
free(p);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (!*username)
|
|
Packit Service |
4684c1 |
return GNUTLS_E_MEMORY_ERROR;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
passwd = getpass("Enter key: ");
|
|
Packit Service |
4684c1 |
if (passwd == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "No key given, aborting...\n");
|
|
Packit Service |
4684c1 |
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
tmp.data = (void *) passwd;
|
|
Packit Service |
4684c1 |
tmp.size = strlen(passwd);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
res_size = tmp.size / 2 + 1;
|
|
Packit Service |
4684c1 |
rawkey = gnutls_malloc(res_size);
|
|
Packit Service |
4684c1 |
if (rawkey == NULL)
|
|
Packit Service |
4684c1 |
return GNUTLS_E_MEMORY_ERROR;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_hex_decode(&tmp, rawkey, &res_size);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error deriving password: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
gnutls_free(rawkey);
|
|
Packit Service |
4684c1 |
gnutls_free(*username);
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
key->data = (void *) rawkey;
|
|
Packit Service |
4684c1 |
key->size = res_size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(DEBUG)) {
|
|
Packit Service |
4684c1 |
char hexkey[41];
|
|
Packit Service |
4684c1 |
res_size = sizeof(hexkey);
|
|
Packit Service |
4684c1 |
ret = gnutls_hex_encode(key, hexkey, &res_size);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error in hex encoding: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
fprintf(stderr, "PSK username: %s\n", *username);
|
|
Packit Service |
4684c1 |
fprintf(stderr, "PSK hint: %s\n", hint);
|
|
Packit Service |
4684c1 |
fprintf(stderr, "PSK key: %s\n", hexkey);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void init_global_tls_stuff(void)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_PKCS11
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PROVIDER)) {
|
|
Packit Service |
4684c1 |
ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "pkcs11_init: %s",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
else {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_pkcs11_add_provider(OPT_ARG(PROVIDER),
|
|
Packit Service |
4684c1 |
NULL);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "pkcs11_add_provider: %s",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* X509 stuff */
|
|
Packit Service |
4684c1 |
if (gnutls_certificate_allocate_credentials(&xcred) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Certificate allocation memory error\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_pin_function(xcred, pin_callback, NULL);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_verify_flags(xcred, global_vflags);
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_flags(xcred, GNUTLS_CERTIFICATE_VERIFY_CRLS);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (x509_cafile != NULL) {
|
|
Packit Service |
4684c1 |
ret = gnutls_certificate_set_x509_trust_file(xcred,
|
|
Packit Service |
4684c1 |
x509_cafile,
|
|
Packit Service |
4684c1 |
x509ctype);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
if (insecure == 0) {
|
|
Packit Service |
4684c1 |
ret = gnutls_certificate_set_x509_system_trust(xcred);
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_UNIMPLEMENTED_FEATURE) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Warning: this system doesn't support a default trust store\n");
|
|
Packit Service |
4684c1 |
ret = 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
ret = 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error setting the x509 trust file: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Processed %d CA certificate(s).\n", ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (x509_crlfile != NULL) {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_x509_crl_file(xcred,
|
|
Packit Service |
4684c1 |
x509_crlfile,
|
|
Packit Service |
4684c1 |
x509ctype);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Error setting the x509 CRL file: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Processed %d CRL(s).\n", ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
load_x509_keys();
|
|
Packit Service |
4684c1 |
load_rawpk_keys();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_SRP
|
|
Packit Service |
4684c1 |
if (srp_username && srp_passwd) {
|
|
Packit Service |
4684c1 |
/* SRP stuff */
|
|
Packit Service |
4684c1 |
if (gnutls_srp_allocate_client_credentials(&srp_cred) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "SRP authentication error\n");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_srp_set_client_credentials_function(srp_cred,
|
|
Packit Service |
4684c1 |
srp_username_callback);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_PSK
|
|
Packit Service |
4684c1 |
/* PSK stuff */
|
|
Packit Service |
4684c1 |
if (gnutls_psk_allocate_client_credentials(&psk_cred) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "PSK authentication error\n");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (psk_username && psk_key.data) {
|
|
Packit Service |
4684c1 |
ret = gnutls_psk_set_client_credentials(psk_cred,
|
|
Packit Service |
4684c1 |
psk_username,
|
|
Packit Service |
4684c1 |
&psk_key,
|
|
Packit Service |
4684c1 |
GNUTLS_PSK_KEY_HEX);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Error setting the PSK credentials: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
gnutls_psk_set_client_credentials_function(psk_cred,
|
|
Packit Service |
4684c1 |
psk_callback);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_ANON
|
|
Packit Service |
4684c1 |
/* ANON stuff */
|
|
Packit Service |
4684c1 |
if (gnutls_anon_allocate_client_credentials(&anon_cred) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Anonymous authentication error\n");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* OCSP check for the peer's certificate. Should be called
|
|
Packit Service |
4684c1 |
* only after the certificate list verification is complete.
|
|
Packit Service |
4684c1 |
* Returns:
|
|
Packit Service |
4684c1 |
* -1: certificate chain could not be checked fully
|
|
Packit Service |
4684c1 |
* >=0: number of certificates verified ok
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_OCSP
|
|
Packit Service |
4684c1 |
static int cert_verify_ocsp(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_t cert, issuer;
|
|
Packit Service |
4684c1 |
const gnutls_datum_t *cert_list;
|
|
Packit Service |
4684c1 |
unsigned int cert_list_size = 0, ok = 0;
|
|
Packit Service |
4684c1 |
unsigned failed = 0;
|
|
Packit Service |
4684c1 |
int deinit_issuer = 0, deinit_cert = 0;
|
|
Packit Service |
4684c1 |
gnutls_datum_t resp;
|
|
Packit Service |
4684c1 |
unsigned char noncebuf[23];
|
|
Packit Service |
4684c1 |
gnutls_datum_t nonce = { noncebuf, sizeof(noncebuf) };
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
unsigned it;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
|
|
Packit Service |
4684c1 |
if (cert_list_size == 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "No certificates found!\n");
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (it = 0; it < cert_list_size; it++) {
|
|
Packit Service |
4684c1 |
if (deinit_cert)
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_deinit(cert);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_x509_crt_init(&cert);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Memory error: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
deinit_cert = 1;
|
|
Packit Service |
4684c1 |
ret = gnutls_x509_crt_import(cert, &cert_list[it], GNUTLS_X509_FMT_DER);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Decoding error: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (deinit_issuer) {
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_deinit(issuer);
|
|
Packit Service |
4684c1 |
deinit_issuer = 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_certificate_get_issuer(xcred, cert, &issuer, 0);
|
|
Packit Service |
4684c1 |
if (ret < 0 && cert_list_size - it > 1) {
|
|
Packit Service |
4684c1 |
ret = gnutls_x509_crt_init(&issuer);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Memory error: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
deinit_issuer = 1;
|
|
Packit Service |
4684c1 |
ret = gnutls_x509_crt_import(issuer, &cert_list[it + 1], GNUTLS_X509_FMT_DER);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Decoding error: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else if (ret < 0) {
|
|
Packit Service |
4684c1 |
if (it == 0)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Cannot find issuer: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_rnd(GNUTLS_RND_NONCE, nonce.data, nonce.size);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "gnutls_rnd: %s", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = send_ocsp_request(NULL, cert, issuer, &resp, &nonce);
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Cannot contact OCSP server\n");
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* verify and check the response for revoked cert */
|
|
Packit Service |
4684c1 |
ret = check_ocsp_response(cert, issuer, &resp, &nonce, verbose);
|
|
Packit Service |
4684c1 |
free(resp.data);
|
|
Packit Service |
4684c1 |
if (ret == 1)
|
|
Packit Service |
4684c1 |
ok++;
|
|
Packit Service |
4684c1 |
else if (ret == 0) {
|
|
Packit Service |
4684c1 |
failed++;
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cleanup:
|
|
Packit Service |
4684c1 |
if (deinit_issuer)
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_deinit(issuer);
|
|
Packit Service |
4684c1 |
if (deinit_cert)
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_deinit(cert);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (failed > 0)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
return ok >= 1 ? (int) ok : -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|