Hi All, Attaching a patch to support OpenPGP certificates for TLS (RFC 6091). This is applicable only when linked with gnutls since only that library supports this RFC.
This allows for TLS authentication based on web-of-trust. Can be paired with apache2 and mod_gnutls (which links with gnutls). Attaching a sample apache2 site configuration. Applies cleanly over commit 5d87b1f22ca044e81c75496f913a7eba34992eee Regards.
gtls: support for OpenPGP certificates (RFC 6091)
gnutls has support for OpenPGP certificates.
mod_gnutls [1] is an apache module that links with
gnutls and supports TLS with OpenPGP certificates.
This commit adds the client-side support.
[1] https://mod.gnutls.org/
diff --git a/configure.ac b/configure.ac
index df1d372..9bb8469 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1836,6 +1836,18 @@ if test "$GNUTLS_ENABLED" = "1"; then
])
fi
+dnl ---
+dnl Check if we can use GnuTLS OpenPGP support.
+dnl ---
+if test "$GNUTLS_ENABLED" = "1"; then
+ AC_CHECK_LIB(gnutls, gnutls_openpgp_crt_init,
+ [
+ AC_DEFINE(HAVE_GNUTLS_OPENPGP, 1, [if you have the function gnutls_openpgp_crt_init])
+ AC_SUBST(HAVE_GNUTLS_OPENPGP, [1])
+ GNUTLS_OPENPGP=1
+ ])
+fi
+
dnl ----------------------------------------------------
dnl check for PolarSSL
dnl ----------------------------------------------------
diff --git a/docs/curl.1 b/docs/curl.1
index 710283f..14d3ee6 100644
--- a/docs/curl.1
+++ b/docs/curl.1
@@ -562,6 +562,22 @@ or no response at all is received, the verification fails.
This is currently only implemented in the OpenSSL, GnuTLS and NSS backends.
(Added in 7.41.0)
+.IP "--openpgp"
+(SSL) Tells curl to enable OpenPGP certificate support during
+TLS handshake according to RFC 6091.
+.IP "--openpgp-keyring <file>"
+(SSL) Tells curl to use the specified OpenPGP keyring file to verify
+for peer when using OpenPGP certificates (\fI--openpgp\fP).
+.IP "--openpgp-cert <file>"
+(SSL) Tells curl to use the specified OpenPGP certificate when client certificate
+is request by the server during a OpenPGP based HTTPS session (\fI--openpgp\fP).
+.IP "--openpgp-key <file>"
+(SSL) Tells curl to use the specified OpenPGP private key when client certificate
+is request by the server during a OpenPGP based HTTPS session (\fI--openpgp\fP).
+.IP "--openpgp-cert-type <type>"
+(SSL) Tells curl what certificate type the provided OpenPGP certificate is in.
+BASE64 and RAW are recognized types.If not specified, BASE64 is assumed.
+If this option is used several times, the last one will be used.
.IP "-f, --fail"
(HTTP) Fail silently (no output at all) on server errors. This is mostly done
to better enable scripts etc to better deal with failed attempts. In normal
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 0a326d3..374dd7e 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1626,6 +1626,21 @@ typedef enum {
/* Set if we should verify the certificate status. */
CINIT(SSL_VERIFYSTATUS, LONG, 232),
+ /* OpenPGP support during TLS handshake according to RFC 6091 */
+ CINIT(SSL_ENABLE_OPENPGP, OBJECTPOINT, 233),
+
+ /* name of the OpenPGP keyring file */
+ CINIT(OPENPGP_KEYRING, OBJECTPOINT, 234),
+
+ /* name of the OpenPGP certficate file */
+ CINIT(OPENPGP_CERT, OBJECTPOINT, 235),
+
+ /* name of the OpenPGP private key file */
+ CINIT(OPENPGP_KEY, OBJECTPOINT, 236),
+
+ /* name of the OpenPGP cert format */
+ CINIT(OPENPGP_CERTTYPE, OBJECTPOINT, 237),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h
index 69d41a2..c15720b 100644
--- a/include/curl/typecheck-gcc.h
+++ b/include/curl/typecheck-gcc.h
@@ -270,6 +270,11 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
(option) == CURLOPT_DNS_LOCAL_IP4 || \
(option) == CURLOPT_DNS_LOCAL_IP6 || \
(option) == CURLOPT_LOGIN_OPTIONS || \
+ (option) == CURLOPT_SSL_ENABLE_OPENPGP || \
+ (option) == CURLOPT_OPENPGP_KEYRING || \
+ (option) == CURLOPT_OPENPGP_CERT || \
+ (option) == CURLOPT_OPENPGP_KEY || \
+ (option) == CURLOPT_OPENPGP_CERTTYPE || \
0)
/* evaluates to true if option takes a curl_write_callback argument */
diff --git a/lib/url.c b/lib/url.c
index 0789825..642f556 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2609,6 +2609,28 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
break;
#endif
+#ifdef HAVE_GNUTLS_OPENPGP
+ case CURLOPT_SSL_ENABLE_OPENPGP:
+ data->set.ssl_openpgp = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_OPENPGP_KEYRING:
+ result = setstropt(&data->set.str[STRING_OPENPGP_KEYRING],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_OPENPGP_CERT:
+ result = setstropt(&data->set.str[STRING_OPENPGP_CERT],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_OPENPGP_KEY:
+ result = setstropt(&data->set.str[STRING_OPENPGP_KEY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_OPENPGP_CERTTYPE:
+ result = setstropt(&data->set.str[STRING_OPENPGP_CERTTYPE],
+ va_arg(param, char *));
+ break;
+#endif
+
default:
/* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION;
diff --git a/lib/urldata.h b/lib/urldata.h
index 50a745f..da401f5 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1434,6 +1434,12 @@ enum dupstring {
#ifdef USE_UNIX_SOCKETS
STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */
#endif
+#ifdef HAVE_GNUTLS_OPENPGP
+ STRING_OPENPGP_KEYRING, /* OpenPGP keyring file name */
+ STRING_OPENPGP_CERT, /* OpenPGP certificate file name */
+ STRING_OPENPGP_KEY, /* OpenPGP private key file name */
+ STRING_OPENPGP_CERTTYPE, /* OpenPGP cert format (BASE64 or RAW) */
+#endif
/* -- end of zero-terminated strings -- */
@@ -1652,6 +1658,9 @@ struct UserDefined {
bool ssl_enable_alpn; /* TLS ALPN extension? */
long expect_100_timeout; /* in milliseconds */
+#ifdef HAVE_GNUTLS_OPENPGP
+ bool ssl_openpgp; /* enable OpenPGP cerificate support */
+#endif
};
struct Names {
diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
index 5b91883..5b99226 100644
--- a/lib/vtls/gtls.c
+++ b/lib/vtls/gtls.c
@@ -35,6 +35,9 @@
#include <gnutls/abstract.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
+#ifdef HAVE_GNUTLS_OPENPGP
+#include <gnutls/openpgp.h>
+#endif
#ifdef USE_GNUTLS_NETTLE
#include <gnutls/crypto.h>
@@ -350,7 +353,7 @@ static CURLcode handshake(struct connectdata *conn,
}
}
-static gnutls_x509_crt_fmt_t do_file_type(const char *type)
+static gnutls_x509_crt_fmt_t do_x509_file_type(const char *type)
{
if(!type || !type[0])
return GNUTLS_X509_FMT_PEM;
@@ -360,6 +363,18 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
return GNUTLS_X509_FMT_DER;
return -1;
}
+#ifdef HAVE_GNUTLS_OPENPGP
+static gnutls_openpgp_crt_fmt_t do_openpgp_file_type(const char *type)
+{
+ if(!type || !type[0])
+ return GNUTLS_OPENPGP_FMT_BASE64;
+ if(Curl_raw_equal(type, "BASE64"))
+ return GNUTLS_OPENPGP_FMT_BASE64;
+ if(Curl_raw_equal(type, "RAW"))
+ return GNUTLS_OPENPGP_FMT_RAW;
+ return -1;
+}
+#endif
static CURLcode
gtls_connect_step1(struct connectdata *conn,
@@ -390,9 +405,15 @@ gtls_connect_step1(struct connectdata *conn,
GNUTLS_CIPHER_3DES_CBC,
};
static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
+#ifdef HAVE_GNUTLS_OPENPGP
+ static const int openpgp_cert_type_priority[] = { GNUTLS_CRT_OPENPGP, GNUTLS_CRT_X509, 0 };
+#endif
static int protocol_priority[] = { 0, 0, 0, 0 };
#else
#define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
+#ifdef HAVE_GNUTLS_OPENPGP
+#define GNUTLS_OPENPGP_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-OPENPGP:+CTYPE-X509"
+#endif
/* If GnuTLS was compiled without support for SRP it will error out if SRP is
requested in the priority string, so treat it specially
*/
@@ -471,6 +492,23 @@ gtls_connect_step1(struct connectdata *conn,
rc, data->set.ssl.CAfile);
}
+#ifdef HAVE_GNUTLS_OPENPGP
+ if(data->set.ssl_openpgp && data->set.str[STRING_OPENPGP_KEYRING]) {
+ rc = gnutls_certificate_set_openpgp_keyring_file(conn->ssl[sockindex].cred,
+ data->set.str[STRING_OPENPGP_KEYRING],
+ GNUTLS_OPENPGP_FMT_RAW);
+ if(rc < 0) {
+ infof(data, "error reading gpg keyring file %s (%s)\n",
+ data->set.str[STRING_OPENPGP_KEYRING], gnutls_strerror(rc));
+ if(data->set.ssl.verifypeer)
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ else
+ infof(data, "successfully read gpg keyring file %s\n",
+ data->set.str[STRING_OPENPGP_KEYRING]);
+ }
+#endif
+
if(data->set.ssl.CRLfile) {
/* set the CRL list file */
rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
@@ -519,6 +557,11 @@ gtls_connect_step1(struct connectdata *conn,
/* Sets the priority on the certificate types supported by gnutls. Priority
is higher for types specified before others. After specifying the types
you want, you must append a 0. */
+#ifdef HAVE_GNUTLS_OPENPGP
+ if(data->set.ssl_openpgp)
+ rc = gnutls_certificate_type_set_priority(session, openpgp_cert_type_priority);
+ else
+#endif
rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
if(rc != GNUTLS_E_SUCCESS)
return CURLE_SSL_CONNECT_ERROR;
@@ -561,6 +604,37 @@ gtls_connect_step1(struct connectdata *conn,
}
#else
+#ifdef HAVE_GNUTLS_OPENPGP
+ if(data->set.ssl_openpgp)
+ switch (data->set.ssl.version) {
+ case CURL_SSLVERSION_SSLv3:
+ prioritylist = GNUTLS_OPENPGP_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
+ sni = false;
+ break;
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ prioritylist = GNUTLS_OPENPGP_CIPHERS ":-VERS-SSL3.0";
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ prioritylist = GNUTLS_OPENPGP_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.0";
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ prioritylist = GNUTLS_OPENPGP_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.1";
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ prioritylist = GNUTLS_OPENPGP_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.2";
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ default:
+ failf(data, "GnuTLS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ break;
+ }
+ else
+#endif
/* Ensure +SRP comes at the *end* of all relevant strings so that it can be
* removed if a run-time error indicates that SRP is not supported by this
* GnuTLS version */
@@ -640,13 +714,30 @@ gtls_connect_step1(struct connectdata *conn,
data->set.str[STRING_CERT],
data->set.str[STRING_KEY] ?
data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
- do_file_type(data->set.str[STRING_CERT_TYPE]) ) !=
+ do_x509_file_type(data->set.str[STRING_CERT_TYPE]) ) !=
GNUTLS_E_SUCCESS) {
failf(data, "error reading X.509 key or certificate file");
return CURLE_SSL_CONNECT_ERROR;
}
}
+#ifdef HAVE_GNUTLS_OPENPGP
+ if(data->set.ssl_openpgp
+ && data->set.str[STRING_OPENPGP_CERT]
+ && data->set.str[STRING_OPENPGP_KEY]) {
+ /* try both base64 and raw */
+ if(gnutls_certificate_set_openpgp_key_file(
+ conn->ssl[sockindex].cred,
+ data->set.str[STRING_OPENPGP_CERT],
+ data->set.str[STRING_OPENPGP_KEY],
+ do_openpgp_file_type(data->set.str[STRING_OPENPGP_CERTTYPE]) ) !=
+ GNUTLS_E_SUCCESS) {
+ failf(data, "error reading OpenPGP key or certificate file");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif
+
#ifdef USE_TLS_SRP
/* put the credentials to the current session */
if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
@@ -755,7 +846,7 @@ static Curl_recv gtls_recv;
static Curl_send gtls_send;
static CURLcode
-gtls_connect_step3(struct connectdata *conn,
+gtls_x509_connect_step3(struct connectdata *conn,
int sockindex)
{
unsigned int cert_list_size;
@@ -1130,6 +1221,243 @@ gtls_connect_step3(struct connectdata *conn,
return result;
}
+#ifdef HAVE_GNUTLS_OPENPGP
+static CURLcode
+gtls_openpgp_connect_step3(struct connectdata *conn,
+ int sockindex)
+{
+ unsigned int cert_list_size;
+ const gnutls_datum *chainp;
+ unsigned int verify_status;
+ gnutls_openpgp_crt_t openpgp_cert;
+ char certbuf[256]; /* big enough? */
+ size_t size;
+ unsigned int algo;
+ unsigned int bits;
+ time_t certclock;
+ const char *ptr;
+ struct SessionHandle *data = conn->data;
+ gnutls_session session = conn->ssl[sockindex].session;
+ int rc;
+ int incache;
+ void *ssl_sessionid;
+ CURLcode result = CURLE_OK;
+ gnutls_certificate_credentials_t cert_cred = NULL;
+
+ /* This function will return the peer's raw certificate (chain) as sent by
+ the peer. These certificates are in raw format (DER encoded for
+ X.509). In case of a X.509 then a certificate list may be present. The
+ first certificate in the list is the peer's certificate, following the
+ issuer's certificate, then the issuer's issuer etc. */
+
+ chainp = gnutls_certificate_get_peers(session, &cert_list_size);
+ if(!chainp) {
+ if(data->set.ssl.verifypeer ||
+ data->set.ssl.verifyhost ||
+ data->set.ssl.issuercert) {
+#ifdef USE_TLS_SRP
+ if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
+ && data->set.ssl.username != NULL
+ && !data->set.ssl.verifypeer
+ && gnutls_cipher_get(session)) {
+ /* no peer cert, but auth is ok if we have SRP user and cipher and no
+ peer verify */
+ }
+ else {
+#endif
+ failf(data, "failed to get server cert");
+ return CURLE_PEER_FAILED_VERIFICATION;
+#ifdef USE_TLS_SRP
+ }
+#endif
+ }
+ infof(data, "\t common name: WARNING couldn't obtain\n");
+ }
+
+ if(data->set.ssl.verifypeer) {
+ /* This function will try to verify the peer's certificate and return its
+ status (trusted, invalid etc.). The value of status should be one or
+ more of the gnutls_certificate_status_t enumerated elements bitwise
+ or'd. To avoid denial of service attacks some default upper limits
+ regarding the certificate key size and chain size are set. To override
+ them use gnutls_certificate_set_verify_limits(). */
+
+ rc = gnutls_certificate_verify_peers2(session, &verify_status);
+ if(rc < 0) {
+ failf(data, "server cert verify failed: %d", rc);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* verify_status is a bitmask of gnutls_certificate_status bits */
+ if((verify_status & GNUTLS_CERT_INVALID) || (verify_status & GNUTLS_CERT_SIGNER_NOT_FOUND)) {
+ if(data->set.ssl.verifypeer) {
+ failf(data, "server certificate verification failed. CAfile: %s "
+ "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
+ data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
+ return CURLE_SSL_CACERT;
+ }
+ else
+ infof(data, "\t server certificate verification FAILED\n");
+ }
+ else
+ infof(data, "\t server certificate verification OK\n");
+ }
+ else
+ infof(data, "\t server certificate verification SKIPPED\n");
+
+ /* initialize an OpenPGP certificate structure. */
+ gnutls_openpgp_crt_init(&openpgp_cert);
+
+ /* convert the given RAW Certificate to the native
+ gnutls_openpgp_crt_t format */
+ gnutls_openpgp_crt_import(openpgp_cert, chainp, GNUTLS_OPENPGP_FMT_RAW);
+
+ size=sizeof(certbuf);
+ rc = gnutls_openpgp_crt_get_name(openpgp_cert, 0, certbuf, &size);
+ if(rc) {
+ infof(data, "error fetching name from cert:%s\n",
+ gnutls_strerror(rc));
+ }
+
+ /* This function will check if the given certificate's subject matches the
+ given hostname. This is a basic implementation of the matching described
+ in RFC2818 (HTTPS), which takes into account wildcards, and the subject
+ alternative name PKIX extension. Returns non zero on success, and zero on
+ failure. */
+ rc = gnutls_openpgp_crt_check_hostname(openpgp_cert, conn->host.name);
+
+ if(!rc) {
+ if(data->set.ssl.verifyhost) {
+ failf(data, "SSL: certificate subject name (%s) does not match "
+ "target host name '%s'", certbuf, conn->host.dispname);
+ gnutls_openpgp_crt_deinit(openpgp_cert);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\t common name: %s (does not match '%s')\n",
+ certbuf, conn->host.dispname);
+ }
+ else
+ infof(data, "\t common name: %s (matched)\n", certbuf);
+
+ /* Check for time-based validity */
+ certclock = gnutls_openpgp_crt_get_expiration_time(openpgp_cert);
+
+ if(certclock == (time_t)-1) {
+ failf(data, "server cert expiration date verify failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ if(certclock < time(NULL)) {
+ if(data->set.ssl.verifypeer) {
+ failf(data, "server certificate expiration date has passed.");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\t server certificate expiration date FAILED\n");
+ }
+ else
+ infof(data, "\t server certificate expiration date OK\n");
+
+ certclock = gnutls_openpgp_crt_get_creation_time(openpgp_cert);
+
+ if(certclock == (time_t)-1) {
+ failf(data, "server cert activation date verify failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ if(certclock > time(NULL)) {
+ if(data->set.ssl.verifypeer) {
+ failf(data, "server certificate creation time is in future. %llu %llu", certclock, time(NULL));
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\t server certificate activation date FAILED\n");
+ }
+ else
+ infof(data, "\t server certificate activation date OK\n");
+ /* Show:
+
+ - ciphers used
+ - subject
+ - start date
+ - expire date
+
+ */
+
+ /* public key algorithm's parameters */
+ algo = gnutls_openpgp_crt_get_pk_algorithm(openpgp_cert, &bits);
+ infof(data, "\t certificate public key: %s\n",
+ gnutls_pk_algorithm_get_name(algo));
+
+ /* version of the X.509 certificate. */
+ infof(data, "\t certificate version: #%d\n",
+ gnutls_openpgp_crt_get_version(openpgp_cert));
+
+
+ size = sizeof(certbuf);
+
+ certclock = gnutls_openpgp_crt_get_expiration_time(openpgp_cert);
+ showtime(data, "expire date", certclock);
+
+ size = sizeof(certbuf);
+
+ gnutls_openpgp_crt_deinit(openpgp_cert);
+
+ /* compression algorithm (if any) */
+ ptr = gnutls_compression_get_name(gnutls_compression_get(session));
+ /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
+ infof(data, "\t compression: %s\n", ptr);
+
+ /* the name of the cipher used. ie 3DES. */
+ ptr = gnutls_cipher_get_name(gnutls_cipher_get(session));
+ infof(data, "\t cipher: %s\n", ptr);
+
+ /* the MAC algorithms name. ie SHA1 */
+ ptr = gnutls_mac_get_name(gnutls_mac_get(session));
+ infof(data, "\t MAC: %s\n", ptr);
+
+ conn->ssl[sockindex].state = ssl_connection_complete;
+ conn->recv[sockindex] = gtls_recv;
+ conn->send[sockindex] = gtls_send;
+
+ {
+ /* we always unconditionally get the session id here, as even if we
+ already got it from the cache and asked to use it in the connection, it
+ might've been rejected and then a new one is in use now and we need to
+ detect that. */
+ void *connect_sessionid;
+ size_t connect_idsize;
+
+ /* get the session ID data size */
+ gnutls_session_get_data(session, NULL, &connect_idsize);
+ connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
+
+ if(connect_sessionid) {
+ /* extract session ID to the allocated buffer */
+ gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+
+ incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL));
+ if(incache) {
+ /* there was one before in the cache, so instead of risking that the
+ previous one was rejected, we just kill that and store the new */
+ Curl_ssl_delsessionid(conn, ssl_sessionid);
+ }
+
+ /* store this session id */
+ result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
+ if(result) {
+ free(connect_sessionid);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ return result;
+}
+#endif
/*
* This function is called after the TCP connect has completed. Setup the TLS
@@ -1163,7 +1491,12 @@ gtls_connect_common(struct connectdata *conn,
/* Finish connecting once the handshake is done */
if(ssl_connect_1==connssl->connecting_state) {
- rc = gtls_connect_step3(conn, sockindex);
+ if (gnutls_certificate_type_get(conn->ssl[sockindex].session) == GNUTLS_CRT_X509)
+ rc = gtls_x509_connect_step3(conn, sockindex);
+#ifdef HAVE_GNUTLS_OPENPGP
+ else
+ rc = gtls_openpgp_connect_step3(conn, sockindex);
+#endif
if(rc)
return rc;
}
diff --git a/packages/OS400/curl.inc.in b/packages/OS400/curl.inc.in
index b3aa29f..c775578 100644
--- a/packages/OS400/curl.inc.in
+++ b/packages/OS400/curl.inc.in
@@ -1207,6 +1207,16 @@
d c 10231
d CURLOPT_CURLOPT_SSL_VERIFYSTATUS...
d c 00232
+ d CURLOPT_SSL_ENABLE_OPENPGP...
+ d c 00233
+ d CURLOPT_OPENPGP_KEYRING...
+ d c 00234
+ d CURLOPT_OPENPGP_CERT...
+ d c 00235
+ d CURLOPT_OPENPGP_KEY...
+ d c 00236
+ d CURLOPT_OPENPGP_CERTTYPE...
+ d c 00237
*
/if not defined(CURL_NO_OLDIES)
d CURLOPT_FILE c 10001
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h
index 4008cd0..75a6f15 100644
--- a/src/tool_cfgable.h
+++ b/src/tool_cfgable.h
@@ -206,6 +206,13 @@ struct OperationConfig {
bool nonpn; /* enable/disable TLS NPN extension */
bool noalpn; /* enable/disable TLS ALPN extension */
char *unix_socket_path; /* path to Unix domain socket */
+#ifdef HAVE_GNUTLS_OPENPGP
+ bool openpgp; /* enable/disable TLS OpenPGP cert_type extension */
+ char *openpgp_keyring; /* OpenPGP keyring file name */
+ char *openpgp_cert; /* OpenPGP certificate file name */
+ char *openpgp_key; /* OpenPGP key file name */
+ char *openpgp_cert_type; /* OpenPGP cert format */
+#endif
struct GlobalConfig *global;
struct OperationConfig *prev;
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
index 5b60c9c..2a624a8 100644
--- a/src/tool_getparam.c
+++ b/src/tool_getparam.c
@@ -177,6 +177,13 @@ static const struct LongShort aliases[]= {
{"$K", "sasl-ir", FALSE},
{"$L", "test-event", FALSE},
{"$M", "unix-socket", TRUE},
+#ifdef HAVE_GNUTLS_OPENPGP
+ {"$N", "openpgp", FALSE},
+ {"$O", "openpgp-keyring", TRUE},
+ {"$P", "openpgp-cert", TRUE},
+ {"$Q", "openpgp-key", TRUE},
+ {"$R", "openpgp-cert-type", TRUE},
+#endif
{"0", "http1.0", FALSE},
{"01", "http1.1", FALSE},
{"02", "http2", FALSE},
@@ -981,6 +988,23 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
case 'M': /* --unix-socket */
GetStr(&config->unix_socket_path, nextarg);
break;
+#ifdef HAVE_GNUTLS_OPENPGP
+ case 'N': /* --openpgp */
+ config->openpgp = toggle;
+ break;
+ case 'O': /* --openpgp-keyring, OpenPGP keyring file name */
+ GetStr(&config->openpgp_keyring, nextarg);
+ break;
+ case 'P': /* --openpgp-cert, OpenPGP certificate file name */
+ GetStr(&config->openpgp_cert, nextarg);
+ break;
+ case 'Q': /* --openpgp-key, OpenPGP private key file name */
+ GetStr(&config->openpgp_key, nextarg);
+ break;
+ case 'R': /* --openpgp-cert-type, OpenPGP cert file type */
+ GetStr(&config->openpgp_cert_type, nextarg);
+ break;
+#endif
}
break;
case '#': /* --progress-bar */
diff --git a/src/tool_help.c b/src/tool_help.c
index 4616211..7897962 100644
--- a/src/tool_help.c
+++ b/src/tool_help.c
@@ -151,6 +151,13 @@ static const char *const helptext[] = {
" --noproxy List of hosts which do not use proxy",
" --ntlm Use HTTP NTLM authentication (H)",
" --oauth2-bearer TOKEN OAuth 2 Bearer Token (IMAP, POP3, SMTP)",
+#ifdef HAVE_GNUTLS_OPENPGP
+ " --openpgp Enable OpenPGP certificate support (SSL)",
+ " --openpgp-keyring FILE OpenPGP keyring file name (SSL)",
+ " --openpgp-cert FILE OpenPGP certificate file name (SSL)",
+ " --openpgp-key FILE OpenPGP private key file name (SSL)",
+ " --openpgp-cert-type FILE OpenPGP certificate format (BASE64/RAW) (SSL)",
+#endif
" -o, --output FILE Write to FILE instead of stdout",
" --pass PASS Pass phrase for the private key (SSL/SSH)",
" --pinnedpubkey FILE Public key (PEM/DER) to verify peer against "
diff --git a/src/tool_operate.c b/src/tool_operate.c
index 35a0dd3..df0fa0a 100644
--- a/src/tool_operate.c
+++ b/src/tool_operate.c
@@ -1347,6 +1347,24 @@ static CURLcode operate_do(struct GlobalConfig *global,
retry_sleep = retry_sleep_default; /* ms */
retrystart = tvnow();
+#ifdef HAVE_GNUTLS_OPENPGP
+ if(config->openpgp) {
+ my_setopt(curl, CURLOPT_SSL_ENABLE_OPENPGP, 1L);
+ }
+ if(config->openpgp_keyring) {
+ my_setopt_str(curl, CURLOPT_OPENPGP_KEYRING, config->openpgp_keyring);
+ }
+ if(config->openpgp_cert) {
+ my_setopt_str(curl, CURLOPT_OPENPGP_CERT, config->openpgp_cert);
+ }
+ if(config->openpgp_key) {
+ my_setopt_str(curl, CURLOPT_OPENPGP_KEY, config->openpgp_key);
+ }
+ if(config->openpgp_cert_type) {
+ my_setopt_str(curl, CURLOPT_OPENPGP_CERTTYPE, config->openpgp_cert_type);
+ }
+#endif
+
#ifndef CURL_DISABLE_LIBCURL_OPTION
result = easysrc_perform();
if(result) {
apache2-openpgp.conf
Description: Binary data
------------------------------------------------------------------- List admin: http://cool.haxx.se/list/listinfo/curl-library Etiquette: http://curl.haxx.se/mail/etiquette.html
