#include "connect.h" /* for the connect timeout */
#include "select.h"
#include "rawstr.h"
+#include "warnless.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
struct in_addr addr;
#endif
#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
- static int cipher_priority[] = { GNUTLS_CIPHER_AES_128_GCM,
- GNUTLS_CIPHER_AES_256_GCM, GNUTLS_CIPHER_AES_128_CBC,
- GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_CAMELLIA_128_CBC,
- GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_CIPHER_3DES_CBC,
+ static const int cipher_priority[] = {
+ /* These two ciphers were added to GnuTLS as late as ver. 3.0.1,
+ but this code path is only ever used for ver. < 2.12.0.
+ GNUTLS_CIPHER_AES_128_GCM,
+ GNUTLS_CIPHER_AES_256_GCM,
+ */
+ GNUTLS_CIPHER_AES_128_CBC,
+ GNUTLS_CIPHER_AES_256_CBC,
+ GNUTLS_CIPHER_CAMELLIA_128_CBC,
+ GNUTLS_CIPHER_CAMELLIA_256_CBC,
+ GNUTLS_CIPHER_3DES_CBC,
};
static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
static int protocol_priority[] = { 0, 0, 0, 0 };
#else
#define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
+/* If GnuTLS was compiled without support for SRP it will error out if SRP is
+ requested in the priority string, so treat it specially
+ */
+#define GNUTLS_SRP "+SRP"
const char* prioritylist;
- const char *err;
+ const char *err = NULL;
#endif
#ifdef HAS_ALPN
int protocols_size = 2;
break;
}
rc = gnutls_protocol_set_priority(session, protocol_priority);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "Did you pass a valid GnuTLS cipher list?");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
#else
+ /* 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 */
switch (data->set.ssl.version) {
case CURL_SSLVERSION_SSLv3:
prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
break;
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
- prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0";
+ prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP;
break;
case CURL_SSLVERSION_TLSv1_0:
prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
- "+VERS-TLS1.0";
+ "+VERS-TLS1.0:" GNUTLS_SRP;
break;
case CURL_SSLVERSION_TLSv1_1:
prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
- "+VERS-TLS1.1";
+ "+VERS-TLS1.1:" GNUTLS_SRP;
break;
case CURL_SSLVERSION_TLSv1_2:
prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
- "+VERS-TLS1.2";
+ "+VERS-TLS1.2:" GNUTLS_SRP;
break;
case CURL_SSLVERSION_SSLv2:
default:
break;
}
rc = gnutls_priority_set_direct(session, prioritylist, &err);
+ if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
+ if(!strcmp(err, GNUTLS_SRP)) {
+ /* This GnuTLS was probably compiled without support for SRP.
+ * Note that fact and try again without it. */
+ int validprioritylen = curlx_uztosi(err - prioritylist);
+ char *prioritycopy = strdup(prioritylist);
+ if(!prioritycopy)
+ return CURLE_OUT_OF_MEMORY;
+
+ infof(data, "This GnuTLS does not support SRP\n");
+ if(validprioritylen)
+ /* Remove the :+SRP */
+ prioritycopy[validprioritylen - 1] = 0;
+ rc = gnutls_priority_set_direct(session, prioritycopy, &err);
+ free(prioritycopy);
+ }
+ }
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "Error %d setting GnuTLS cipher list starting with %s",
+ rc, err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
#endif
#ifdef HAS_ALPN
}
#endif
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "Did you pass a valid GnuTLS cipher list?");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
-
if(data->set.str[STRING_CERT]) {
if(gnutls_certificate_set_x509_key_file(
conn->ssl[sockindex].cred,
unsigned int verify_status;
gnutls_x509_crt_t x509_cert,x509_issuer;
gnutls_datum_t issuerp;
- char certbuf[256]; /* big enough? */
+ char certbuf[256] = ""; /* big enough? */
size_t size;
unsigned int algo;
unsigned int bits;
alternative name PKIX extension. Returns non zero on success, and zero on
failure. */
rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
+#if GNUTLS_VERSION_NUMBER < 0x030306
+ /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
+ addresses. */
+ if(!rc) {
+#ifdef ENABLE_IPV6
+ #define use_addr in6_addr
+#else
+ #define use_addr in_addr
+#endif
+ unsigned char addrbuf[sizeof(struct use_addr)];
+ unsigned char certaddr[sizeof(struct use_addr)];
+ size_t addrlen = 0, certaddrlen;
+ int i;
+ int ret = 0;
+
+ if(Curl_inet_pton(AF_INET, conn->host.name, addrbuf) > 0)
+ addrlen = 4;
+#ifdef ENABLE_IPV6
+ else if(Curl_inet_pton(AF_INET6, conn->host.name, addrbuf) > 0)
+ addrlen = 16;
+#endif
+ if(addrlen) {
+ for(i=0; ; i++) {
+ certaddrlen = sizeof(certaddr);
+ ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
+ &certaddrlen, NULL);
+ /* If this happens, it wasn't an IP address. */
+ if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+ continue;
+ if(ret < 0)
+ break;
+ if(ret != GNUTLS_SAN_IPADDRESS)
+ continue;
+ if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
+ rc = 1;
+ break;
+ }
+ }
+ }
+ }
+#endif
if(!rc) {
if(data->set.ssl.verifyhost) {
failf(data, "SSL: certificate subject name (%s) does not match "
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;
+ size_t connect_idsize = 0;
/* get the session ID data size */
gnutls_session_get_data(session, NULL, &connect_idsize);