Example #1
0
/* In GnuTLS 2.12 since we don't have a normal privkey and hence can't just
   use gnutls_privkey_sign_data() with it, we have to jump through hoops to
   prepare the hash in exactly the right way and call our internal TPM
   signing function. */
int gtls2_tpm_sign_dummy_data(struct openconnect_info *vpninfo,
			      const gnutls_datum_t *data,
			      gnutls_datum_t *sig)
{
	static const unsigned char ber_encode[15] = {
		0x30, 0x21, /* SEQUENCE, length 31 */
		0x30, 0x09,   /* SEQUENCE, length 9 */
		0x06, 0x05,      /* OBJECT_ID, length 5 */
		0x2b, 0x0e, 0x03, 0x02, 0x1a,  /* SHA1 OID: 1.3.14.3.2.26 */
		0x05, 0x00,      /* NULL (parameters) */
		0x04, 0x14,   /* OCTET_STRING, length 20 */
		/* followed by the 20-byte sha1 */
	};
	gnutls_datum_t hash;
	unsigned char digest[sizeof(ber_encode) + SHA1_SIZE];
	size_t shalen = SHA1_SIZE;
	int err;

	err = gnutls_fingerprint(GNUTLS_DIG_SHA1, data,
				 &digest[sizeof(ber_encode)], &shalen);
	if (err) {
		vpn_progress(vpninfo, PRG_ERR,
			     _("Failed to SHA1 input data for signing: %s\n"),
			     gnutls_strerror(err));
		return err;
	}

	memcpy(digest, ber_encode, sizeof(ber_encode));

	hash.data = digest;
	hash.size = sizeof(digest);

	return tpm_sign_fn(NULL, vpninfo, &hash, sig);
}
Example #2
0
         const unsigned char* gtlsGeneric::generateSha1(const unsigned char* _data, size_t _data_size)
         {
            static unsigned char hash[20];
            size_t result_size = 20;

            unsigned char* buffer = new unsigned char[_data_size];
            memcpy(buffer, _data, _data_size);

            gnutls_datum_t data;
            data.data = buffer;
            data.size = _data_size;

            if (gnutls_fingerprint(SHA_DIGEST, &data, hash, &result_size) < 0)
               {
                  // BTG_NOTICE("gtlsGeneric::generateSha1() failed");
                  delete [] buffer;
                  buffer = 0;
                  return 0;
               }

            delete [] buffer;
            buffer = 0;

            return hash;
         }
Example #3
0
unsigned int ma_ssl_get_finger_print(MARIADB_SSL *cssl, unsigned char *fp, unsigned int len)
{
  MYSQL *mysql;
  size_t fp_len= len;
  const gnutls_datum_t *cert_list;
  unsigned int cert_list_size;

  if (!cssl || !cssl->ssl)
    return 0;

  mysql= (MYSQL *)gnutls_session_get_ptr(cssl->ssl);

  cert_list = gnutls_certificate_get_peers (cssl->ssl, &cert_list_size);
  if (cert_list == NULL)
  {
    my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
                        ER(CR_SSL_CONNECTION_ERROR), 
                        "Unable to get server certificate");
    return 0;
  }

  if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &cert_list[0], fp, &fp_len) == 0)
    return fp_len;
  else
  {
    my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
                        ER(CR_SSL_CONNECTION_ERROR), 
                        "Finger print buffer too small");
    return 0;
  }
}
Example #4
0
static void vncws_send_handshake_response(VncState *vs, const char* key)
{
    char combined_key[WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1];
    unsigned char hash[SHA1_DIGEST_LEN];
    size_t hash_size = sizeof(hash);
    char *accept = NULL, *response = NULL;
    gnutls_datum_t in;
    int ret;

    g_strlcpy(combined_key, key, WS_CLIENT_KEY_LEN + 1);
    g_strlcat(combined_key, WS_GUID, WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1);

    /* hash and encode it */
    in.data = (void *)combined_key;
    in.size = WS_CLIENT_KEY_LEN + WS_GUID_LEN;
    ret = gnutls_fingerprint(GNUTLS_DIG_SHA1, &in, hash, &hash_size);
    if (ret == GNUTLS_E_SUCCESS && hash_size <= SHA1_DIGEST_LEN) {
        accept = g_base64_encode(hash, hash_size);
    }
    if (accept == NULL) {
        VNC_DEBUG("Hashing Websocket combined key failed\n");
        vnc_client_error(vs);
        return;
    }

    response = g_strdup_printf(WS_HANDSHAKE, accept);
    vnc_client_write_buf(vs, (const uint8_t *)response, strlen(response));

    g_free(accept);
    g_free(response);

    vs->encode_ws = 1;
    vnc_init_state(vs);
}
Example #5
0
static void ssl_vfy_fp(struct sockifo* ifo) {
	unsigned int i;
	uint8_t result[41];
	size_t resultsiz = 20;
	if (!ifo->fingerprint) {
		esock(ifo, "No fingerprint given");
		return;
	}
	const gnutls_datum_t* cert = gnutls_certificate_get_peers(ifo->ssl, &i);
	if (i < 1) {
		esock(ifo, "No certificate given to fingerprint");
		return;
	}
	int rv = gnutls_fingerprint(GNUTLS_DIG_SHA1, cert, result + 20, &resultsiz);
	if (rv) {
		esock(ifo, gnutls_strerror(rv));
		return;
	}
	for(i=0; i < 20; i++) {
		uint8_t v = result[20+i];
		result[2*i  ] = hex[v / 16];
		result[2*i+1] = hex[v % 16];
	}
	result[40] = 0;
	char* fp = ifo->fingerprint - 1;
	while (fp) {
		if (!memcmp(result, fp + 1, 40))
			return;
		fp = strchr(fp + 1, ',');
	}
	snprintf(errbuf, sizeof(errbuf), "SSL fingerprint error: got %s expected %s", result, ifo->fingerprint);
	esock(ifo, errbuf);
}
Example #6
0
bool_t SSLi_getSHA1Hash(SSL_handle_t *session, uint8_t *hash)
{
	gnutls_datum_t const * certificateData = gnutls_certificate_get_peers(*session, NULL);

	size_t resultSize = 0;
	int error = gnutls_fingerprint( GNUTLS_DIG_SHA1, certificateData, hash, &resultSize);
	return error == GNUTLS_E_SUCCESS && resultSize == 20;
}
Example #7
0
InfoHash
InfoHash::get(const uint8_t* data, size_t data_len)
{
    InfoHash h;
    size_t s = h.size();
    const gnutls_datum_t gnudata = {(uint8_t*)data, (unsigned)data_len};
    const gnutls_digest_algorithm_t algo =  (HASH_LEN == 64) ? GNUTLS_DIG_SHA512 : (
            (HASH_LEN == 32) ? GNUTLS_DIG_SHA256 : (
                (HASH_LEN == 20) ? GNUTLS_DIG_SHA1   :
                GNUTLS_DIG_NULL ));
    static_assert(algo != GNUTLS_DIG_NULL, "Can't find hash function to use.");
    int rc = gnutls_fingerprint(algo, &gnudata, h.data(), &s);
    if (rc == 0 && s == HASH_LEN)
        return h;
    throw std::string("Error while hashing");
}
Example #8
0
/**
 * tls_fingerprint - Create a fingerprint of a TLS Certificate
 * @param algo   Fingerprint algorithm, e.g. GNUTLS_MAC_SHA256
 * @param buf    Buffer for the fingerprint
 * @param buflen Length of the buffer
 * @param data Certificate
 */
static void tls_fingerprint(gnutls_digest_algorithm_t algo, char *buf,
                            size_t buflen, const gnutls_datum_t *data)
{
  unsigned char md[64];
  size_t n;

  n = 64;

  if (gnutls_fingerprint(algo, data, (char *) md, &n) < 0)
  {
    snprintf(buf, buflen, _("[unable to calculate]"));
  }
  else
  {
    for (int i = 0; i < (int) n; i++)
    {
      char ch[8];
      snprintf(ch, 8, "%02X%s", md[i], ((i % 2) ? " " : ""));
      mutt_str_strcat(buf, buflen, ch);
    }
    buf[2 * n + n / 2 - 1] = '\0'; /* don't want trailing space */
  }
}
Example #9
0
static void tls_fingerprint (gnutls_digest_algorithm algo,
                             char* s, int l, const gnutls_datum* data)
{
  unsigned char md[36];
  size_t n;
  int j;

  n = 36;

  if (gnutls_fingerprint (algo, data, (char *)md, &n) < 0)
  {
    snprintf (s, l, _("[unable to calculate]"));
  }
  else
  {
    for (j = 0; j < (int) n; j++)
    {
      char ch[8];
      snprintf (ch, 8, "%02X%s", md[j], (j % 2 ? " " : ""));
      safe_strcat (s, l, ch);
    }
    s[2*n+n/2-1] = '\0'; /* don't want trailing space */
  }
}
Example #10
0
std::string Authenticator::computeDigestResponse(std::string &method, std::string &uri) {
#if HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
    // The "response" field is computed as:
    //    md5(md5(<username>:<realm>:<password>):<nonce>:md5(<cmd>:<url>))
    size_t md5len = 16;
    unsigned char md5buf[md5len];
    char md5HexBuf[md5len*2+1];
    
    // Step 1: md5(<username>:<realm>:<password>)
    std::string ha1Data = username() + ":" + realm() + ":" + password();
	Debug( 2, "HA1 pre-md5: %s", ha1Data.c_str() );
#if HAVE_DECL_MD5
    MD5((unsigned char*)ha1Data.c_str(), ha1Data.length(), md5buf);
#elif HAVE_DECL_GNUTLS_FINGERPRINT
    gnutls_datum_t md5dataha1 = { (unsigned char*)ha1Data.c_str(), ha1Data.length() };
    gnutls_fingerprint( GNUTLS_DIG_MD5, &md5dataha1, md5buf, &md5len );
#endif
    for ( unsigned int j = 0; j < md5len; j++ )
    {
        sprintf(&md5HexBuf[2*j], "%02x", md5buf[j] );
    }
    md5HexBuf[md5len*2]='\0';
    std::string ha1Hash = md5HexBuf;
    
    // Step 2: md5(<cmd>:<url>)
    std::string ha2Data = method + ":" + uri;
	Debug( 2, "HA2 pre-md5: %s", ha2Data.c_str() );
#if HAVE_DECL_MD5
    MD5((unsigned char*)ha2Data.c_str(), ha2Data.length(), md5buf );
#elif HAVE_DECL_GNUTLS_FINGERPRINT
    gnutls_datum_t md5dataha2 = { (unsigned char*)ha2Data.c_str(), ha2Data.length() };
    gnutls_fingerprint( GNUTLS_DIG_MD5, &md5dataha2, md5buf, &md5len );
#endif
    for ( unsigned int j = 0; j < md5len; j++ )
    {
        sprintf( &md5HexBuf[2*j], "%02x", md5buf[j] );
    }
    md5HexBuf[md5len*2]='\0';
    std::string ha2Hash = md5HexBuf;

    // Step 3: md5(ha1:<nonce>:ha2)
    std::string digestData = ha1Hash + ":" + nonce();
	if ( ! fQop.empty() ) {
		digestData += ":" + stringtf("%08x", nc) + ":"+fCnonce + ":" + fQop;
		nc ++;
		// if qop was specified, then we have to include t and a cnonce and an nccount
	}
	digestData += ":" + ha2Hash;
	Debug( 2, "pre-md5: %s", digestData.c_str() );
#if HAVE_DECL_MD5
    MD5((unsigned char*)digestData.c_str(), digestData.length(), md5buf);
#elif HAVE_DECL_GNUTLS_FINGERPRINT
    gnutls_datum_t md5datadigest = { (unsigned char*)digestData.c_str(), digestData.length() };
    gnutls_fingerprint( GNUTLS_DIG_MD5, &md5datadigest, md5buf, &md5len );
#endif
    for ( unsigned int j = 0; j < md5len; j++ )
    {
        sprintf( &md5HexBuf[2*j], "%02x", md5buf[j] );
    }
    md5HexBuf[md5len*2]='\0';
   
    return md5HexBuf;
#else // HAVE_DECL_MD5
	Error( "You need to build with gnutls or openssl installed to use digest authentication" );
    return( 0 );
#endif // HAVE_DECL_MD5
}
Example #11
0
// Function to validate an authentication string
User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) {
#if HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
#ifdef HAVE_GCRYPT_H
  // Special initialisation for libgcrypt
  if ( !gcry_check_version( GCRYPT_VERSION ) ) {
    Fatal( "Unable to initialise libgcrypt" );
  }
  gcry_control( GCRYCTL_DISABLE_SECMEM, 0 );
  gcry_control( GCRYCTL_INITIALIZATION_FINISHED, 0 );
#endif // HAVE_GCRYPT_H

  const char *remote_addr = "";
  if ( use_remote_addr ) {
    remote_addr = getenv( "REMOTE_ADDR" );
    if ( !remote_addr ) {
      Warning( "Can't determine remote address, using null" );
      remote_addr = "";
    }
  }

  Debug( 1, "Attempting to authenticate user from auth string '%s'", auth );
  char sql[ZM_SQL_SML_BUFSIZ] = "";
  snprintf( sql, sizeof(sql), "SELECT Id, Username, Password, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds FROM Users WHERE Enabled = 1" );

  if ( mysql_query( &dbconn, sql ) ) {
    Error( "Can't run query: %s", mysql_error( &dbconn ) );
    exit( mysql_errno( &dbconn ) );
  }

  MYSQL_RES *result = mysql_store_result( &dbconn );
  if ( !result ) {
    Error( "Can't use query result: %s", mysql_error( &dbconn ) );
    exit( mysql_errno( &dbconn ) );
  }
  int n_users = mysql_num_rows( result );

  if ( n_users < 1 ) {
    mysql_free_result( result );
    Warning( "Unable to authenticate user" );
    return( 0 );
  }

  while( MYSQL_ROW dbrow = mysql_fetch_row( result ) ) {
    const char *user = dbrow[1];
    const char *pass = dbrow[2];

    char auth_key[512] = "";
    char auth_md5[32+1] = "";
    size_t md5len = 16;
    unsigned char md5sum[md5len];

    time_t now = time( 0 );
    unsigned int hours = config.auth_hash_ttl;

    if ( ! hours ) {
      Warning("No value set for ZM_AUTH_HASH_TTL. Defaulting to 2.");
      hours = 2;
    } else {
      Debug( 1, "AUTH_HASH_TTL is %d", hours );
    }

    for ( unsigned int i = 0; i < hours; i++, now -= 3600 ) {
      struct tm *now_tm = localtime( &now );

      snprintf( auth_key, sizeof(auth_key), "%s%s%s%s%d%d%d%d", 
        config.auth_hash_secret,
        user,
        pass,
        remote_addr,
        now_tm->tm_hour,
        now_tm->tm_mday,
        now_tm->tm_mon,
        now_tm->tm_year
      );

#if HAVE_DECL_MD5
      MD5( (unsigned char *)auth_key, strlen(auth_key), md5sum );
#elif HAVE_DECL_GNUTLS_FINGERPRINT
      gnutls_datum_t md5data = { (unsigned char *)auth_key, strlen(auth_key) };
      gnutls_fingerprint( GNUTLS_DIG_MD5, &md5data, md5sum, &md5len );
#endif
      auth_md5[0] = '\0';
      for ( unsigned int j = 0; j < md5len; j++ ) {
        sprintf( &auth_md5[2*j], "%02x", md5sum[j] );
      }
      Debug( 1, "Checking auth_key '%s' -> auth_md5 '%s' == '%s'", auth_key, auth_md5, auth );

      if ( !strcmp( auth, auth_md5 ) ) {
        // We have a match
        User *user = new User( dbrow );
        Debug(1, "Authenticated user '%s'", user->getUsername() );
        mysql_free_result( result );
        return( user );
      } else {
        Debug(1, "No match for %s", auth );
      }
    }
  }
  mysql_free_result( result );
#else // HAVE_DECL_MD5
  Error( "You need to build with gnutls or openssl installed to use hash based authentication" );
#endif // HAVE_DECL_MD5
  Debug(1, "No user found for auth_key %s", auth );
  return 0;
}
Example #12
0
static gboolean
ssl_verify_certificate (LmSSL *ssl, const gchar *server)
{
    LmSSLBase *base;
    unsigned int        status;
    int rc;

    base = LM_SSL_BASE (ssl);

    /* This verification function uses the trusted CAs in the credentials
     * structure. So you must have installed one or more CA certificates.
     */
    rc = gnutls_certificate_verify_peers2 (ssl->gnutls_session, &status);

    if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND) {
        if (base->func (ssl,
                        LM_SSL_STATUS_NO_CERT_FOUND,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (rc != 0) {
        if (base->func (ssl,
                        LM_SSL_STATUS_GENERIC_ERROR,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND) {
        if (base->func (ssl,
                        LM_SSL_STATUS_NO_CERT_FOUND,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (status & GNUTLS_CERT_INVALID
        || status & GNUTLS_CERT_REVOKED) {
        if (base->func (ssl, LM_SSL_STATUS_UNTRUSTED_CERT,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (gnutls_certificate_expiration_time_peers (ssl->gnutls_session) < time (0)) {
        if (base->func (ssl, LM_SSL_STATUS_CERT_EXPIRED,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (gnutls_certificate_activation_time_peers (ssl->gnutls_session) > time (0)) {
        if (base->func (ssl, LM_SSL_STATUS_CERT_NOT_ACTIVATED,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (gnutls_certificate_type_get (ssl->gnutls_session) == GNUTLS_CRT_X509) {
        const gnutls_datum_t* cert_list;
        guint cert_list_size;
        gnutls_digest_algorithm_t digest = GNUTLS_DIG_SHA256;
        guchar digest_bin[LM_FINGERPRINT_LENGTH];
        size_t digest_size;
        gnutls_x509_crt_t cert;

        cert_list = gnutls_certificate_get_peers (ssl->gnutls_session, &cert_list_size);
        if (cert_list == NULL) {
            if (base->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND,
                            base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
                return FALSE;
            }
        }

        gnutls_x509_crt_init (&cert);

        if (gnutls_x509_crt_import (cert, &cert_list[0],
                                    GNUTLS_X509_FMT_DER) != 0) {
            if (base->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND,
                            base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
                return FALSE;
            }
        }

        if (!gnutls_x509_crt_check_hostname (cert, server)) {
            if (base->func (ssl, LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
                            base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
                return FALSE;
            }
        }

        gnutls_x509_crt_deinit (cert);

        digest_size = gnutls_hash_get_len(digest);
        g_assert(digest_size < sizeof(digest_bin));

        if (gnutls_fingerprint (digest,
                                &cert_list[0],
                                digest_bin,
                                &digest_size) >= 0) {
            _lm_ssl_base_set_fingerprint(base, digest_bin, digest_size);
            if (_lm_ssl_base_check_fingerprint(base) != 0 &&
                base->func (ssl,
                            LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH,
                            base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
                return FALSE;
            }
        }
        else if (base->func (ssl, LM_SSL_STATUS_GENERIC_ERROR,
                             base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    return TRUE;
}
Example #13
0
/* This function will print information about this session's peer
 * certificate. */
static void
logcertinfo (gnutls_session_t session)
{
  time_t now = time (NULL);
  const gnutls_datum_t *cert_list;
  unsigned cert_list_size = 0;
  gnutls_x509_crt_t cert;
  size_t i;
  int rc;

  cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
  if (!cert_list)
    return;

  rc = gnutls_x509_crt_init (&cert);
  if (rc < 0)
    {
      syslog (LOG_ERR | LOG_DAEMON, "TLS xci failed (%d): %s",
	      rc, gnutls_strerror (rc));
      return;
    }

  if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
    for (i = 0; i < cert_list_size; i++)
      {
	time_t expiration_time, activation_time;
	char *expiration_time_str = NULL, *activation_time_str = NULL;
	unsigned char *serial = NULL, *serialhex = NULL;
	char *issuer = NULL, *subject = NULL;
	size_t seriallen, issuerlen, subjectlen;
	unsigned char md5fingerprint[16], md5fingerprinthex[3 * 16 + 1];
	size_t md5fingerprintlen;
	int algo;
	unsigned bits;
	const char *keytype, *validity;

	rc = gnutls_x509_crt_import (cert, &cert_list[i],
				     GNUTLS_X509_FMT_DER);
	if (rc < 0)
	  {
	    syslog (LOG_ERR | LOG_DAEMON, "TLS xci[%zu] failed (%d): %s",
		    i, rc, gnutls_strerror (rc));
	    goto cleanup;
	  }

	md5fingerprintlen = sizeof (md5fingerprint);
	rc = gnutls_fingerprint (GNUTLS_DIG_MD5, &cert_list[i],
				 md5fingerprint, &md5fingerprintlen);
	if (rc != GNUTLS_E_SUCCESS)
	  {
	    syslog (LOG_ERR | LOG_DAEMON, "TLS f[%zu] failed (%d): %s",
		    i, rc, gnutls_strerror (rc));
	    goto cleanup;
	  }

	for (i = 0; i < md5fingerprintlen; i++)
	  sprintf ((char *) &md5fingerprinthex[3 * i], "%.2x:",
		   md5fingerprint[i]);

	expiration_time = gnutls_x509_crt_get_expiration_time (cert);
	if (expiration_time == (time_t) - 1)
	  {
	    syslog (LOG_ERR | LOG_DAEMON, "TLS xcget[%zu] failed (%d): %s",
		    i, rc, gnutls_strerror (rc));
	    goto cleanup;
	  }

	activation_time = gnutls_x509_crt_get_activation_time (cert);
	if (expiration_time == (time_t) - 1)
	  {
	    syslog (LOG_ERR | LOG_DAEMON, "TLS xcgat[%zu] failed (%d): %s",
		    i, rc, gnutls_strerror (rc));
	    goto cleanup;
	  }

	expiration_time_str = xstrdup (ctime (&expiration_time));
	if (expiration_time_str[strlen (expiration_time_str) - 1] == '\n')
	  expiration_time_str[strlen (expiration_time_str) - 1] = '\0';

	activation_time_str = xstrdup (ctime (&activation_time));
	if (activation_time_str[strlen (activation_time_str) - 1] == '\n')
	  activation_time_str[strlen (activation_time_str) - 1] = '\0';

	rc = gnutls_x509_crt_get_dn (cert, NULL, &subjectlen);
	if (rc != GNUTLS_E_SUCCESS && rc != GNUTLS_E_SHORT_MEMORY_BUFFER)
	  {
	    syslog (LOG_ERR | LOG_DAEMON, "TLS xcgd[%zu] failed (%d): %s",
		    i, rc, gnutls_strerror (rc));
	    goto cleanup;
	  }
	subject = xmalloc (++subjectlen);
	rc = gnutls_x509_crt_get_dn (cert, subject, &subjectlen);
	if (rc != GNUTLS_E_SUCCESS)
	  {
	    syslog (LOG_ERR | LOG_DAEMON, "TLS xcgd2[%zu] failed (%d): %s",
		    i, rc, gnutls_strerror (rc));
	    goto cleanup;
	  }

	rc = gnutls_x509_crt_get_issuer_dn (cert, NULL, &issuerlen);
	if (rc != GNUTLS_E_SUCCESS && rc != GNUTLS_E_SHORT_MEMORY_BUFFER)
	  {
	    syslog (LOG_ERR | LOG_DAEMON, "TLS xcgid[%zu] failed (%d): %s",
		    i, rc, gnutls_strerror (rc));
	    goto cleanup;
	  }
	issuer = xmalloc (++issuerlen);
	rc = gnutls_x509_crt_get_issuer_dn (cert, issuer, &issuerlen);
	if (rc != GNUTLS_E_SUCCESS)
	  {
	    syslog (LOG_ERR | LOG_DAEMON, "TLS xcgid2[%zu] failed (%d): %s",
		    i, rc, gnutls_strerror (rc));
	    goto cleanup;
	  }

	seriallen = 0;
	rc = gnutls_x509_crt_get_serial (cert, NULL, &seriallen);
	if (rc != GNUTLS_E_SUCCESS && rc != GNUTLS_E_SHORT_MEMORY_BUFFER)
	  {
	    syslog (LOG_ERR | LOG_DAEMON, "TLS xcgs[%zu] failed (%d): %s",
		    i, rc, gnutls_strerror (rc));
	    goto cleanup;
	  }
	serial = xmalloc (seriallen);
	rc = gnutls_x509_crt_get_serial (cert, serial, &seriallen);
	if (rc != GNUTLS_E_SUCCESS)
	  {
	    syslog (LOG_ERR | LOG_DAEMON, "TLS xcgs2[%zu] failed (%d): %s",
		    i, rc, gnutls_strerror (rc));
	    goto cleanup;
	  }

	serialhex = xmalloc (2 * seriallen + 1);
	for (i = 0; i < seriallen; i++)
	  sprintf ((char *) &serialhex[2 * i], "%.2x", serial[i]);

	algo = gnutls_x509_crt_get_pk_algorithm (cert, &bits);
	if (algo == GNUTLS_PK_RSA)
	  keytype = "RSA modulus";
	else if (algo == GNUTLS_PK_DSA)
	  keytype = "DSA exponent";
	else
	  keytype = "UNKNOWN";

	if (expiration_time < now)
	  validity = "EXPIRED";
	else if (activation_time > now)
	  validity = "NOT YET ACTIVATED";
	else
	  validity = "valid";

	/* This message can arguably belong to LOG_AUTH.  */
	syslog (LOG_INFO, "TLS client certificate `%s', issued by `%s', "
		"serial number `%s', MD5 fingerprint `%s', activated `%s', "
		"expires `%s', version #%d, key %s %d bits, currently %s",
		subject, issuer, serialhex, md5fingerprinthex,
		activation_time_str, expiration_time_str,
		gnutls_x509_crt_get_version (cert), keytype, bits, validity);

      cleanup:
	free (serialhex);
	free (serial);
	free (expiration_time_str);
	free (activation_time_str);
	free (issuer);
	free (subject);
      }

  gnutls_x509_crt_deinit (cert);

  {
    unsigned int status;

    /* Accept default syslog facility for these errors.
     * They are clearly relevant as audit traces.  */
    rc = gnutls_certificate_verify_peers2 (session, &status);
    if (rc != GNUTLS_E_SUCCESS)
      syslog (LOG_ERR, "TLS client certificate failed (%d): %s",
	      rc, gnutls_strerror (rc));
    if (status != 0)
      syslog (LOG_ERR, "TLS client certificate verify failure (%d)",
	      status);
  }
}
Example #14
0
static gboolean
ssl_verify_certificate (LmSSL *ssl, const gchar *server)
{
	int           status;

	/* This verification function uses the trusted CAs in the credentials
	 * structure. So you must have installed one or more CA certificates.
	 */
	status = gnutls_certificate_verify_peers (ssl->gnutls_session);

	if (status == GNUTLS_E_NO_CERTIFICATE_FOUND) {
		if (ssl->func (ssl,
			       LM_SSL_STATUS_NO_CERT_FOUND,
			       ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
			return FALSE;
		}
	}
	
	if (status & GNUTLS_CERT_INVALID
	    || status & GNUTLS_CERT_REVOKED) {
		if (ssl->func (ssl, LM_SSL_STATUS_UNTRUSTED_CERT,
			       ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
			return FALSE;
		}
	}
	
	if (gnutls_certificate_expiration_time_peers (ssl->gnutls_session) < time (0)) {
		if (ssl->func (ssl, LM_SSL_STATUS_CERT_EXPIRED,
			       ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
			return FALSE;
		}
	}
	
	if (gnutls_certificate_activation_time_peers (ssl->gnutls_session) > time (0)) {
		if (ssl->func (ssl, LM_SSL_STATUS_CERT_NOT_ACTIVATED,
			       ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
			return FALSE;
		}
	}
	
	if (gnutls_certificate_type_get (ssl->gnutls_session) == GNUTLS_CRT_X509) {
		const gnutls_datum* cert_list;
		guint cert_list_size;
		size_t digest_size;
		gnutls_x509_crt cert;
		
		cert_list = gnutls_certificate_get_peers (ssl->gnutls_session, &cert_list_size);
		if (cert_list == NULL) {
			if (ssl->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND,
				       ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
				return FALSE;
			}
		}

		gnutls_x509_crt_init (&cert);

		if (!gnutls_x509_crt_import (cert, &cert_list[0],
					     GNUTLS_X509_FMT_DER)) {
			if (ssl->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND, 
				       ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
				return FALSE;
			}
		}
		
		if (!gnutls_x509_crt_check_hostname (cert, server)) {
			if (ssl->func (ssl, LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
				       ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
				return FALSE;
			}
		}

		gnutls_x509_crt_deinit (cert);

		if (gnutls_fingerprint (GNUTLS_DIG_MD5, &cert_list[0],
					     ssl->fingerprint,
					     &digest_size) >= 0) {
			if (ssl->expected_fingerprint &&
			    memcmp (ssl->expected_fingerprint, ssl->fingerprint,
				    digest_size) &&
			    ssl->func (ssl,
				       LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH,
				       ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
				return FALSE;
			}
		} 
		else if (ssl->func (ssl, LM_SSL_STATUS_GENERIC_ERROR,
				    ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
			return FALSE; 
		} 
	}

	return TRUE;
}