summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSahana Prasad <sahana@redhat.com>2020-09-01 23:16:53 +0200
committerSahana Prasad <sahana@redhat.com>2020-09-02 18:22:05 +0200
commitf748e8df7f7220656be116f2e354fc3aabbdde67 (patch)
tree6d2e04d04bb610a3a643159ec03bcfe6f1a1ce9c
parent423a1565d280107edd92684714ee22356200b038 (diff)
downloadgnutls-f748e8df7f7220656be116f2e354fc3aabbdde67.tar.gz
src/cli: adds new option '--ca-auto-retrieve' that can be used with gnutls-cli to
automatically download missing intermediate CAs in a certificate chain lib/cred-cert.c : adds set and get APIs to get user data in the gnutls_x509_trust_list_set_getissuer_function() callback. Signed-off-by: Sahana Prasad <sahana@redhat.com>
-rw-r--r--NEWS2
-rw-r--r--devel/libgnutls-latest-x86_64.abi2
-rw-r--r--devel/symbols.last2
-rw-r--r--doc/Makefile.am4
-rw-r--r--doc/manpages/Makefile.am2
-rw-r--r--lib/cert-cred.c35
-rw-r--r--lib/includes/gnutls/x509.h4
-rw-r--r--lib/libgnutls.map2
-rw-r--r--lib/x509/verify-high.h2
-rw-r--r--src/cli-args.def8
-rw-r--r--src/cli.c196
11 files changed, 255 insertions, 4 deletions
diff --git a/NEWS b/NEWS
index 175eb785ff..bc102b4eaf 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,8 @@ See the end for copying conditions.
** API and ABI modifications:
gnutls_x509_trust_list_set_getissuer_function: Added
+gnutls_x509_trust_list_get_ptr: Added
+gnutls_x509_trust_list_set_ptr: Added
* Version 3.6.14 (released 2020-06-03)
diff --git a/devel/libgnutls-latest-x86_64.abi b/devel/libgnutls-latest-x86_64.abi
index 2242bcc785..7f0ddd46c7 100644
--- a/devel/libgnutls-latest-x86_64.abi
+++ b/devel/libgnutls-latest-x86_64.abi
@@ -1259,6 +1259,7 @@
<elf-symbol name='gnutls_x509_trust_list_get_issuer' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_x509_trust_list_get_issuer_by_dn' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_x509_trust_list_get_issuer_by_subject_key_id' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='gnutls_x509_trust_list_get_ptr' version='GNUTLS_3_7_0' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_x509_trust_list_init' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_x509_trust_list_iter_deinit' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_x509_trust_list_iter_get_ca' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -1266,6 +1267,7 @@
<elf-symbol name='gnutls_x509_trust_list_remove_trust_file' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_x509_trust_list_remove_trust_mem' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_x509_trust_list_set_getissuer_function' version='GNUTLS_3_7_0' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='gnutls_x509_trust_list_set_ptr' version='GNUTLS_3_7_0' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_x509_trust_list_verify_crt2' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_x509_trust_list_verify_crt' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_x509_trust_list_verify_named_crt' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
diff --git a/devel/symbols.last b/devel/symbols.last
index d9a5289b7d..c671c3dcda 100644
--- a/devel/symbols.last
+++ b/devel/symbols.last
@@ -1242,6 +1242,7 @@ gnutls_x509_trust_list_deinit@GNUTLS_3_4
gnutls_x509_trust_list_get_issuer@GNUTLS_3_4
gnutls_x509_trust_list_get_issuer_by_dn@GNUTLS_3_4
gnutls_x509_trust_list_get_issuer_by_subject_key_id@GNUTLS_3_4
+gnutls_x509_trust_list_get_ptr@GNUTLS_3_7_0
gnutls_x509_trust_list_init@GNUTLS_3_4
gnutls_x509_trust_list_iter_deinit@GNUTLS_3_4
gnutls_x509_trust_list_iter_get_ca@GNUTLS_3_4
@@ -1249,6 +1250,7 @@ gnutls_x509_trust_list_remove_cas@GNUTLS_3_4
gnutls_x509_trust_list_remove_trust_file@GNUTLS_3_4
gnutls_x509_trust_list_remove_trust_mem@GNUTLS_3_4
gnutls_x509_trust_list_set_getissuer_function@GNUTLS_3_7_0
+gnutls_x509_trust_list_set_ptr@GNUTLS_3_7_0
gnutls_x509_trust_list_verify_crt2@GNUTLS_3_4
gnutls_x509_trust_list_verify_crt@GNUTLS_3_4
gnutls_x509_trust_list_verify_named_crt@GNUTLS_3_4
diff --git a/doc/Makefile.am b/doc/Makefile.am
index d8b2d02ce5..e1834016b1 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -2875,6 +2875,8 @@ FUNCS += functions/gnutls_x509_trust_list_get_issuer_by_dn
FUNCS += functions/gnutls_x509_trust_list_get_issuer_by_dn.short
FUNCS += functions/gnutls_x509_trust_list_get_issuer_by_subject_key_id
FUNCS += functions/gnutls_x509_trust_list_get_issuer_by_subject_key_id.short
+FUNCS += functions/gnutls_x509_trust_list_get_ptr
+FUNCS += functions/gnutls_x509_trust_list_get_ptr.short
FUNCS += functions/gnutls_x509_trust_list_init
FUNCS += functions/gnutls_x509_trust_list_init.short
FUNCS += functions/gnutls_x509_trust_list_iter_deinit
@@ -2889,6 +2891,8 @@ FUNCS += functions/gnutls_x509_trust_list_remove_trust_mem
FUNCS += functions/gnutls_x509_trust_list_remove_trust_mem.short
FUNCS += functions/gnutls_x509_trust_list_set_getissuer_function
FUNCS += functions/gnutls_x509_trust_list_set_getissuer_function.short
+FUNCS += functions/gnutls_x509_trust_list_set_ptr
+FUNCS += functions/gnutls_x509_trust_list_set_ptr.short
FUNCS += functions/gnutls_x509_trust_list_verify_crt
FUNCS += functions/gnutls_x509_trust_list_verify_crt.short
FUNCS += functions/gnutls_x509_trust_list_verify_crt2
diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index 6a16687c01..c1043bca4a 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -1239,6 +1239,7 @@ APIMANS += gnutls_x509_trust_list_deinit.3
APIMANS += gnutls_x509_trust_list_get_issuer.3
APIMANS += gnutls_x509_trust_list_get_issuer_by_dn.3
APIMANS += gnutls_x509_trust_list_get_issuer_by_subject_key_id.3
+APIMANS += gnutls_x509_trust_list_get_ptr.3
APIMANS += gnutls_x509_trust_list_init.3
APIMANS += gnutls_x509_trust_list_iter_deinit.3
APIMANS += gnutls_x509_trust_list_iter_get_ca.3
@@ -1246,6 +1247,7 @@ APIMANS += gnutls_x509_trust_list_remove_cas.3
APIMANS += gnutls_x509_trust_list_remove_trust_file.3
APIMANS += gnutls_x509_trust_list_remove_trust_mem.3
APIMANS += gnutls_x509_trust_list_set_getissuer_function.3
+APIMANS += gnutls_x509_trust_list_set_ptr.3
APIMANS += gnutls_x509_trust_list_verify_crt.3
APIMANS += gnutls_x509_trust_list_verify_crt2.3
APIMANS += gnutls_x509_trust_list_verify_named_crt.3
diff --git a/lib/cert-cred.c b/lib/cert-cred.c
index a5b9493ab4..06a7054330 100644
--- a/lib/cert-cred.c
+++ b/lib/cert-cred.c
@@ -914,6 +914,41 @@ void gnutls_x509_trust_list_set_getissuer_function(gnutls_x509_trust_list_t tlis
tlist->issuer_callback = func;
}
+/**
+ * gnutls_x509_trust_list_set_ptr:
+ * @tlist: is a #gnutls_x509_trust_list_t type.
+ * @ptr: is the user pointer
+ *
+ * This function will set (associate) the user given pointer @ptr to
+ * the tlist structure. This pointer can be accessed with
+ * gnutls_x509_trust_list_get_ptr(). Useful in the callback function
+ * gnutls_x509_trust_list_set_getissuer_function.
+ *
+ * Since: 3.7.0
+ **/
+void gnutls_x509_trust_list_set_ptr(gnutls_x509_trust_list_t tlist, void *ptr)
+{
+ tlist->usr_ptr = ptr;
+}
+
+/**
+ * gnutls_x509_trust_list_get_ptr:
+ * @tlist: is a #gnutls_x509_trust_list_t type.
+ *
+ * Get user pointer for tlist. Useful in callback function
+ * gnutls_x509_trust_list_set_getissuer_function.
+ * This is the pointer set with gnutls_x509_trust_list_set_ptr().
+ *
+ * Returns: the user given pointer from the tlist structure, or
+ * %NULL if it was never set.
+ *
+ * Since: 3.7.0
+ **/
+void *gnutls_x509_trust_list_get_ptr(gnutls_x509_trust_list_t tlist)
+{
+ return tlist->usr_ptr;
+}
+
#define TEST_TEXT "test text"
/* returns error if the certificate has different algorithm than
* the given key parameters.
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index 444c9f0494..c0c509dc11 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -1704,6 +1704,10 @@ typedef int gnutls_x509_trust_list_getissuer_function(gnutls_x509_trust_list_t t
void gnutls_x509_trust_list_set_getissuer_function(gnutls_x509_trust_list_t tlist,
gnutls_x509_trust_list_getissuer_function *func);
+void gnutls_x509_trust_list_set_ptr(gnutls_x509_trust_list_t tlist, void *ptr);
+
+void *gnutls_x509_trust_list_get_ptr(gnutls_x509_trust_list_t tlist);
+
void gnutls_certificate_set_trust_list
(gnutls_certificate_credentials_t res,
gnutls_x509_trust_list_t tlist, unsigned flags);
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index e29f064a30..61276e5340 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1335,6 +1335,8 @@ GNUTLS_3_7_0
{
global:
gnutls_x509_trust_list_set_getissuer_function;
+ gnutls_x509_trust_list_get_ptr;
+ gnutls_x509_trust_list_set_ptr;
local:
*;
} GNUTLS_3_4;
diff --git a/lib/x509/verify-high.h b/lib/x509/verify-high.h
index 6ce5f958ae..4cbb29a9c8 100644
--- a/lib/x509/verify-high.h
+++ b/lib/x509/verify-high.h
@@ -45,6 +45,8 @@ struct gnutls_x509_trust_list_st {
/* set this callback if the issuer in the certificate
* chain is missing. */
gnutls_x509_trust_list_getissuer_function *issuer_callback;
+ /* set user pointer. */
+ void *usr_ptr;
};
int _gnutls_trustlist_inlist(gnutls_x509_trust_list_t list,
diff --git a/src/cli-args.def b/src/cli-args.def
index ac04591325..2279b9cc0a 100644
--- a/src/cli-args.def
+++ b/src/cli-args.def
@@ -477,6 +477,14 @@ flag = {
doc = "This option makes the client to block waiting for the resumption data under TLS1.3. The option has effect only when --resume is provided.";
};
+flag = {
+ name = ca-auto-retrieve;
+ descrip = "Enable automatic retrieval of missing CA certificates";
+ disabled;
+ disable = "no";
+ doc = "This option enables the client to automatically retrieve the missing intermediate CA certificates in the certificate chain, based on the Authority Information Access (AIA) extension.";
+};
+
doc-section = {
ds-type = 'SEE ALSO'; // or anything else
ds-format = 'texi'; // or texi or mdoc format
diff --git a/src/cli.c b/src/cli.c
index cf0ef2ac98..a451dc3bdd 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -76,6 +76,11 @@
#define MAX_BUF 4096
+#define HEADER_PATTERN "GET /%s HTTP/1.0\r\n" \
+ "Host: %s\r\n" \
+ "Accept: */*\r\n" \
+ "Connection: close\r\n\r\n"
+
/* global stuff here */
int resume, starttls, insecure, ranges, rehandshake, udp, mtu,
inline_commands, waitresumption;
@@ -118,6 +123,10 @@ static gnutls_certificate_credentials_t xcred;
static void check_server_cmd(socket_st * socket, int ret);
static void init_global_tls_stuff(void);
static int cert_verify_ocsp(gnutls_session_t session);
+static const char *host_from_url(const char *url, unsigned int *port, const char **path);
+static size_t get_data(void *buf, size_t size, size_t nmemb, void *userp);
+static int getissuer_callback(const gnutls_x509_trust_list_t tlist,
+ const gnutls_x509_crt_t cert);
#define MAX_CRT 6
static unsigned int x509_crt_size;
@@ -1949,6 +1958,7 @@ psk_callback(gnutls_session_t session, char **username,
static void init_global_tls_stuff(void)
{
+ gnutls_x509_trust_list_t tlist;
int ret;
#ifdef ENABLE_PKCS11
@@ -1980,13 +1990,24 @@ static void init_global_tls_stuff(void)
gnutls_certificate_set_verify_flags(xcred, global_vflags);
gnutls_certificate_set_flags(xcred, GNUTLS_CERTIFICATE_VERIFY_CRLS);
+ if (gnutls_x509_trust_list_init(&tlist, 0) < 0) {
+ fprintf(stderr, "Trust list allocation memory error\n");
+ exit(1);
+ }
+ gnutls_certificate_set_trust_list(xcred, tlist, 0);
+
if (x509_cafile != NULL) {
- ret = gnutls_certificate_set_x509_trust_file(xcred,
- x509_cafile,
- x509ctype);
+ ret = gnutls_x509_trust_list_add_trust_file(tlist,
+ x509_cafile,
+ NULL,
+ x509ctype,
+ GNUTLS_TL_USE_IN_TLS,
+ 0);
} else {
if (insecure == 0) {
- ret = gnutls_certificate_set_x509_system_trust(xcred);
+ ret = gnutls_x509_trust_list_add_system_trust(tlist,
+ GNUTLS_TL_USE_IN_TLS,
+ 0);
if (ret == GNUTLS_E_UNIMPLEMENTED_FEATURE) {
fprintf(stderr, "Warning: this system doesn't support a default trust store\n");
ret = 0;
@@ -2002,6 +2023,9 @@ static void init_global_tls_stuff(void)
log_msg(stdout, "Processed %d CA certificate(s).\n", ret);
}
+ if (ENABLED_OPT(CA_AUTO_RETRIEVE))
+ gnutls_x509_trust_list_set_getissuer_function(tlist, getissuer_callback);
+
if (x509_crlfile != NULL) {
ret =
gnutls_certificate_set_x509_crl_file(xcred,
@@ -2165,3 +2189,167 @@ cleanup:
return ok >= 1 ? (int) ok : -1;
}
#endif
+
+/* returns the host part of a URL */
+static const char *host_from_url(const char *url, unsigned int *port, const char **path)
+{
+ static char buffer[512];
+ char *p;
+
+ *port = 0;
+ *path = "";
+
+ if ((p = strstr(url, "http://")) != NULL) {
+ snprintf(buffer, sizeof(buffer), "%s", p + 7);
+ p = strchr(buffer, '/');
+ if (p != NULL) {
+ *p = 0;
+ *path = p+1;
+ }
+
+ p = strchr(buffer, ':');
+ if (p != NULL) {
+ *p = 0;
+ *port = atoi(p + 1);
+ }
+
+ return buffer;
+ } else {
+ return url;
+ }
+}
+
+static size_t get_data(void *buf, size_t size, size_t nmemb, void *userp)
+{
+ gnutls_datum_t *ud = userp;
+
+ size *= nmemb;
+
+ ud->data = realloc(ud->data, size + ud->size);
+ if (ud->data == NULL) {
+ fprintf(stderr, "Not enough memory for the request\n");
+ exit(1);
+ }
+
+ memcpy(&ud->data[ud->size], buf, size);
+ ud->size += size;
+
+ return size;
+}
+
+/* Returns 0 on ok, and -1 on error */
+static int
+getissuer_callback(const gnutls_x509_trust_list_t tlist,
+ const gnutls_x509_crt_t cert)
+{
+ gnutls_datum_t ud;
+ int ret;
+ gnutls_datum_t resp;
+ char *url = NULL;
+ char headers[1024];
+ char _service[16];
+ unsigned char *p;
+ const char *_hostname;
+ const char *path = "";
+ unsigned i;
+ unsigned int headers_size = 0, port;
+ socket_st hd;
+ gnutls_x509_crt_t issuer;
+ gnutls_datum_t data = { NULL, 0 };
+ static char buffer[MAX_BUF + 1];
+
+ sockets_init();
+
+ i = 0;
+ do {
+ ret = gnutls_x509_crt_get_authority_info_access(cert, i++,
+ GNUTLS_IA_CAISSUERS_URI,
+ &data,
+ NULL);
+ } while (ret == GNUTLS_E_UNKNOWN_ALGORITHM);
+
+ if (ret < 0) {
+ fprintf(stderr,
+ "*** Cannot find caIssuer URI in certificate: %s\n",
+ gnutls_strerror(ret));
+ return 0;
+ }
+
+ url = malloc(data.size + 1);
+ if (url == NULL) {
+ return -1;
+ }
+ memcpy(url, data.data, data.size);
+ url[data.size] = 0;
+
+ gnutls_free(data.data);
+
+ _hostname = host_from_url(url, &port, &path);
+ if (port != 0)
+ snprintf(_service, sizeof(_service), "%u", port);
+ else
+ strcpy(_service, "80");
+
+ fprintf(stderr, "Connecting to caIssuer server: %s...\n", _hostname);
+
+ memset(&ud, 0, sizeof(ud));
+
+ snprintf(headers, sizeof(headers), HEADER_PATTERN, path, _hostname);
+ headers_size = strlen(headers);
+
+ socket_open(&hd, _hostname, _service, NULL, SOCKET_FLAG_RAW|SOCKET_FLAG_SKIP_INIT, CONNECT_MSG, NULL);
+ socket_send(&hd, headers, headers_size);
+
+ do {
+ ret = socket_recv(&hd, buffer, sizeof(buffer));
+ if (ret > 0)
+ get_data(buffer, ret, 1, &ud);
+ } while (ret > 0);
+
+ if (ret < 0 || ud.size == 0) {
+ perror("recv");
+ ret = -1;
+ socket_bye(&hd, 0);
+ goto cleanup;
+ }
+
+ socket_bye(&hd, 0);
+
+ p = memmem(ud.data, ud.size, "\r\n\r\n", 4);
+ if (p == NULL) {
+ fprintf(stderr, "Cannot interpret HTTP response\n");
+ ret = -1;
+ goto cleanup;
+ }
+ p += 4;
+ resp.size = ud.size - (p - ud.data);
+ resp.data = p;
+
+ ret = gnutls_x509_crt_init(&issuer);
+ if (ret < 0) {
+ fprintf(stderr, "Memory error\n");
+ ret = -1;
+ goto cleanup;
+ }
+ ret = gnutls_x509_crt_import(issuer, &resp, GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ fprintf(stderr, "Decoding error: %s\n", gnutls_strerror(ret));
+ ret = -1;
+ goto cleanup;
+ }
+ ret = gnutls_x509_trust_list_add_cas(tlist, &issuer, 1, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Memory error\n");
+ ret = -1;
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ gnutls_free(data.data);
+ free(ud.data);
+ free(url);
+
+ return ret;
+}