Example #1
0
/**
 * lm_ssl_get_fingerprint:
 * @ssl: an #LmSSL
 *
 * Returns the fingerprint of the remote server's certificate.
 *
 * Return value: A null terminated string representing the fingerprint or %NULL if unknown.
 **/
const gchar *
lm_ssl_get_fingerprint (LmSSL *ssl)
{
    g_return_val_if_fail (ssl != NULL, NULL);

    return LM_SSL_BASE(ssl)->fingerprint;
}
Example #2
0
/**
 * lm_ssl_get_require_starttls:
 *
 * Return value: TRUE if @ssl requires that STARTTLS succeed.
 **/
gboolean
lm_ssl_get_require_starttls (LmSSL *ssl)
{
    LmSSLBase *base;

    base = LM_SSL_BASE (ssl);
    return base->require_starttls;
}
Example #3
0
/**
 * lm_ssl_ref:
 * @ssl: an #LmSSL
 *
 * Adds a reference to @ssl.
 *
 * Return value: the ssl
 **/
LmSSL *
lm_ssl_ref (LmSSL *ssl)
{
    g_return_val_if_fail (ssl != NULL, NULL);

    LM_SSL_BASE(ssl)->ref_count++;

    return ssl;
}
Example #4
0
void
_lm_ssl_free (LmSSL *ssl)
{
    SSL_CTX_free(ssl->ssl_ctx);
    ssl->ssl_ctx = NULL;

    _lm_ssl_base_free_fields (LM_SSL_BASE(ssl));
    g_free (ssl);
}
Example #5
0
/**
 * lm_ssl_use_starttls:
 * @ssl: an #LmSSL
 *
 * Set whether STARTTLS should be used.
 **/
void
lm_ssl_use_starttls (LmSSL *ssl,
                     gboolean use_starttls,
                     gboolean require_starttls)
{
    LmSSLBase *base;

    base = LM_SSL_BASE (ssl);
    base->use_starttls = use_starttls;
    base->require_starttls = require_starttls;
}
Example #6
0
/**
 * lm_ssl_unref
 * @ssl: an #LmSSL
 *
 * Removes a reference from @ssl. When no more references are present
 * @ssl is freed.
 **/
void
lm_ssl_unref (LmSSL *ssl)
{
    LmSSLBase *base;

    g_return_if_fail (ssl != NULL);

    base = LM_SSL_BASE (ssl);

    base->ref_count --;

    if (base->ref_count == 0) {
        if (base->data_notify) {
            (* base->data_notify) (base->func_data);
        }

        _lm_ssl_free (ssl);
    }
}
Example #7
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 #8
0
void
_lm_ssl_free (LmSSL *ssl)
{
    _lm_ssl_base_free_fields (LM_SSL_BASE (ssl));
    g_free (ssl);
}
Example #9
0
gboolean
_lm_ssl_begin (LmSSL *ssl, gint fd, const gchar *server, GError **error)
{
    int ret;
    LmSSLBase *base;
    gboolean auth_ok = TRUE;

    base = LM_SSL_BASE(ssl);
    gnutls_init (&ssl->gnutls_session, GNUTLS_CLIENT);
    if (base->cipher_list) {
        gnutls_priority_set_direct (ssl->gnutls_session, base->cipher_list, NULL);
    } else {
        gnutls_priority_set_direct (ssl->gnutls_session, "NORMAL", NULL);
    }
    if (base->ca_path) {
        _lm_ssl_set_ca(ssl, base->ca_path);
    } else {
        gnutls_certificate_set_x509_system_trust(ssl->gnutls_xcred);
    }
    gnutls_credentials_set (ssl->gnutls_session,
                            GNUTLS_CRD_CERTIFICATE,
                            ssl->gnutls_xcred);

    gnutls_transport_set_ptr (ssl->gnutls_session,
                              (gnutls_transport_ptr_t)(glong) fd);

    ret = gnutls_handshake (ssl->gnutls_session);

    if (ret >= 0) {
        auth_ok = ssl_verify_certificate (ssl, server);
    }

    if (ret < 0 || !auth_ok) {
        char *errmsg;

        if (!auth_ok) {
            errmsg = "authentication error";
        } else {
            errmsg = "handshake failed";
        }

        g_set_error (error,
                     LM_ERROR, LM_ERROR_CONNECTION_OPEN,
                     "*** GNUTLS %s: %s",
                     errmsg, gnutls_strerror (ret));

        return FALSE;
    }

    lm_verbose ("GNUTLS negotiated cipher suite: %s",
                gnutls_cipher_suite_get_name(gnutls_kx_get(ssl->gnutls_session),
                                             gnutls_cipher_get(ssl->gnutls_session),
                                             gnutls_mac_get(ssl->gnutls_session)));
    lm_verbose ("GNUTLS negotiated compression: %s",
                gnutls_compression_get_name (gnutls_compression_get
                                             (ssl->gnutls_session)));

    ssl->started = TRUE;

    return TRUE;
}
Example #10
0
/**
 * lm_ssl_set_ca:
 * @ssl: an #LmSSL
 * @ca_path: path to a certificate or a directory containing certificates
 *
 * Sets a path to certificates which should be trusted.
 *
 **/
void
lm_ssl_set_ca (LmSSL *ssl, const gchar    *ca_path)
{
  _lm_ssl_base_set_ca_path(LM_SSL_BASE(ssl), ca_path);
}
Example #11
0
/**
 * lm_ssl_set_cipher_list:
 * @ssl: an #LmSSL
 * @cipher_list: list of ciphers
 *
 * Sets the list of availeble ciphers.
 *
 **/
void
lm_ssl_set_cipher_list (LmSSL       *ssl,
                        const gchar *cipher_list)
{
  _lm_ssl_base_set_cipher_list(LM_SSL_BASE(ssl), cipher_list);
}
Example #12
0
static gboolean
ssl_verify_certificate (LmSSL *ssl, const gchar *server)
{
    gboolean retval = TRUE;
    LmSSLBase *base;
    long verify_res;
    unsigned int digest_len;
    X509 *srv_crt;
    gchar *cn;
    X509_NAME *crt_subj;

    base = LM_SSL_BASE(ssl);

    g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
           "%s: Cipher: %s/%s/%i\n",
           __FILE__,
           SSL_get_cipher_version(ssl->ssl),
           SSL_get_cipher_name(ssl->ssl),
           SSL_get_cipher_bits(ssl->ssl, NULL));

    verify_res = SSL_get_verify_result(ssl->ssl);
    srv_crt = SSL_get_peer_certificate(ssl->ssl);
    if (base->expected_fingerprint != NULL) {
        X509_digest(srv_crt, EVP_md5(), (guchar *) base->fingerprint,
                    &digest_len);
        if (memcmp(base->expected_fingerprint, base->fingerprint,
                   digest_len) != 0) {
            if (base->func(ssl,
                           LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH,
                           base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
                return FALSE;
            }
        }
    }
    g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
           "%s: SSL_get_verify_result() = %ld\n",
           __FILE__,
           verify_res);
    switch (verify_res) {
    case X509_V_OK:
        break;
    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
        /* special case for self signed certificates? */
    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
    case X509_V_ERR_UNABLE_TO_GET_CRL:
    case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
        if (base->func(ssl,
                       LM_SSL_STATUS_NO_CERT_FOUND,
                       base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            retval = FALSE;
        }
        break;
    case X509_V_ERR_INVALID_CA:
    case X509_V_ERR_CERT_UNTRUSTED:
    case X509_V_ERR_CERT_REVOKED:
        if (base->func(ssl,
                       LM_SSL_STATUS_UNTRUSTED_CERT,
                       base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            retval = FALSE;
        }
        break;
    case X509_V_ERR_CERT_NOT_YET_VALID:
    case X509_V_ERR_CRL_NOT_YET_VALID:
        if (base->func(ssl,
                       LM_SSL_STATUS_CERT_NOT_ACTIVATED,
                       base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            retval = FALSE;
        }
        break;
    case X509_V_ERR_CERT_HAS_EXPIRED:
    case X509_V_ERR_CRL_HAS_EXPIRED:
        if (base->func(ssl,
                       LM_SSL_STATUS_CERT_EXPIRED,
                       base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            retval = FALSE;
        }
        break;
    default:
        if (base->func(ssl, LM_SSL_STATUS_GENERIC_ERROR,
                       base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            retval = FALSE;
        }
    }
    /*if (retval == FALSE) {
      g_set_error (error, LM_ERROR, LM_ERROR_CONNECTION_OPEN,
      ssl_get_x509_err(verify_res), NULL);
      }*/
    crt_subj = X509_get_subject_name(srv_crt);
    cn = (gchar *) g_malloc0(LM_SSL_CN_MAX + 1);
    
    if (X509_NAME_get_text_by_NID(crt_subj, NID_commonName, cn, LM_SSL_CN_MAX) > 0) {
        gchar *domain = cn;

        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
               "%s: server = '%s', cn = '%s'\n",
               __FILE__, server, cn);
        
        if ((cn[0] == '*') && (cn[1] == '.')) {
            domain = strstr (cn, server);
        }

        if ((domain == NULL) || (strncmp (server, domain, LM_SSL_CN_MAX) != 0)) {
            if (base->func (ssl,
                            LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
                            base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
                retval = FALSE;
            }
        }
    } else {
        g_warning ("X509_NAME_get_text_by_NID() failed");
    }

    g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, 
           "%s:\n\tIssuer: %s\n\tSubject: %s\n\tFor: %s\n",
           __FILE__,
           X509_NAME_oneline(X509_get_issuer_name(srv_crt), NULL, 0),
           X509_NAME_oneline(X509_get_subject_name(srv_crt), NULL, 0),
           cn);

    g_free(cn);
    
    return retval;
}
Example #13
0
gboolean
_lm_ssl_begin (LmSSL *ssl, gint fd, const gchar *server, GError **error)
{
    gint ssl_ret;
    GIOStatus status;
    LmSSLBase *base;

    base = LM_SSL_BASE(ssl);
    if (!ssl->ssl_ctx) {
        g_set_error (error,
                     LM_ERROR, LM_ERROR_CONNECTION_OPEN,
                     "No SSL Context for OpenSSL");
        return FALSE;
    }

    if (base->cipher_list) {
        SSL_CTX_set_cipher_list(ssl->ssl_ctx, base->cipher_list);
    }
    if (base->ca_path) {
        _lm_ssl_set_ca (ssl, base->ca_path);
    } else {
        SSL_CTX_set_default_verify_paths (ssl->ssl_ctx);
    }

    ssl->ssl = SSL_new(ssl->ssl_ctx);
    if (ssl->ssl == NULL) {
        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "SSL_new() == NULL");
        g_set_error(error, LM_ERROR, LM_ERROR_CONNECTION_OPEN,
                    "SSL_new()");
        return FALSE;
    }

    if (!SSL_set_fd (ssl->ssl, fd)) {
        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "SSL_set_fd() failed");
        g_set_error(error, LM_ERROR, LM_ERROR_CONNECTION_OPEN,
                    "SSL_set_fd()");
        return FALSE;
    }
    /*ssl->bio = BIO_new_socket (fd, BIO_NOCLOSE);
      if (ssl->bio == NULL) {
      g_warning("BIO_new_socket() failed");
      g_set_error(error, LM_ERROR, LM_ERROR_CONNECTION_OPEN,
      "BIO_new_socket()");
      return FALSE;
      }
      SSL_set_bio(ssl->ssl, ssl->bio, ssl->bio);*/

    do {
        ssl_ret = SSL_connect(ssl->ssl);
        if (ssl_ret <= 0) {
            status = ssl_io_status_from_return(ssl, ssl_ret);
            if (status != G_IO_STATUS_AGAIN) {
                ssl_print_state(ssl, "SSL_connect",
                                ssl_ret);
                g_set_error(error, LM_ERROR,
                            LM_ERROR_CONNECTION_OPEN,
                            "SSL_connect()");
                return FALSE;
            }

        }
    } while (ssl_ret <= 0);

    if (!ssl_verify_certificate (ssl, server)) {
        g_set_error (error, LM_ERROR, LM_ERROR_CONNECTION_OPEN,
                     "*** SSL certificate verification failed");
        return FALSE;
    }

    return TRUE;
}
Example #14
0
/* side effect: fills the ssl->fingerprint buffer */
static gboolean
ssl_verify_certificate (LmSSL *ssl, const gchar *server)
{
    gboolean retval = TRUE;
    gboolean match_result = FALSE;
    LmSSLBase *base;
    long verify_res;
    int rc;
    const EVP_MD *digest = EVP_sha256();
    unsigned int digest_len;
    guchar digest_bin[EVP_MD_size(digest)];
    X509 *srv_crt;
    gchar *cn;
    X509_NAME *crt_subj;

    base = LM_SSL_BASE(ssl);

    g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
           "%s: Cipher: %s/%s/%i\n",
           __FILE__,
           SSL_get_cipher_version(ssl->ssl),
           SSL_get_cipher_name(ssl->ssl),
           SSL_get_cipher_bits(ssl->ssl, NULL));

    verify_res = SSL_get_verify_result(ssl->ssl);
    srv_crt = SSL_get_peer_certificate(ssl->ssl);
    rc = X509_digest(srv_crt, digest, digest_bin, &digest_len);
    if ((rc != 0) && (digest_len == EVP_MD_size(digest))) {
        _lm_ssl_base_set_fingerprint(base, digest_bin, digest_len);
        if (_lm_ssl_base_check_fingerprint(base) != 0) {
            if (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;
      }
    }
    g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
           "%s: SSL_get_verify_result() = %ld\n",
           __FILE__,
           verify_res);
    switch (verify_res) {
    case X509_V_OK:
        break;
    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
    case X509_V_ERR_UNABLE_TO_GET_CRL:
        if (base->func(ssl,
                       LM_SSL_STATUS_NO_CERT_FOUND,
                       base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            retval = FALSE;
        }
        break;
    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
        /* special case for self signed certificates? */
    case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
    case X509_V_ERR_INVALID_CA:
    case X509_V_ERR_CERT_UNTRUSTED:
    case X509_V_ERR_CERT_REVOKED:
        if (base->func(ssl,
                       LM_SSL_STATUS_UNTRUSTED_CERT,
                       base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            retval = FALSE;
        }
        break;
    case X509_V_ERR_CERT_NOT_YET_VALID:
    case X509_V_ERR_CRL_NOT_YET_VALID:
        if (base->func(ssl,
                       LM_SSL_STATUS_CERT_NOT_ACTIVATED,
                       base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            retval = FALSE;
        }
        break;
    case X509_V_ERR_CERT_HAS_EXPIRED:
    case X509_V_ERR_CRL_HAS_EXPIRED:
        if (base->func(ssl,
                       LM_SSL_STATUS_CERT_EXPIRED,
                       base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            retval = FALSE;
        }
        break;
    default:
        if (base->func(ssl, LM_SSL_STATUS_GENERIC_ERROR,
                       base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            retval = FALSE;
        }
    }
    /*if (retval == FALSE) {
      g_set_error (error, LM_ERROR, LM_ERROR_CONNECTION_OPEN,
      ssl_get_x509_err(verify_res), NULL);
      }*/
    crt_subj = X509_get_subject_name(srv_crt);
    cn = (gchar *) g_malloc0(LM_SSL_CN_MAX + 1);

    /* FWB: deprecated call, can only get first entry */
    if (X509_NAME_get_text_by_NID(crt_subj, NID_commonName, cn, LM_SSL_CN_MAX) > 0) {

        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
               "%s: server = '%s', cn = '%s'\n",
               __FILE__, server, cn);

        if (cn != NULL && ssl_match_domain_name(server, cn)) {
            match_result = TRUE;
        } else {
            /* g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: CN does not match server name\n", __FILE__); */
        }
    } else {
        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
               "X509_NAME_get_text_by_NID() failed");
    }

    /* RFC6125: "...However, it is perfectly acceptable for the subject field to be empty,
     * as long as the certificate contains a subject alternative name ("subjectAltName")
     * extension that includes at least one subjectAltName entry"
     */
    if (!match_result) {
        /* FWB: CN doesn't match, try SANs */
        int subject_alt_names_nb = -1;
        int san_counter;
        STACK_OF(GENERAL_NAME) *subject_alt_names = NULL;

        // Try to extract the names within the SAN extension from the certificate
        subject_alt_names = X509_get_ext_d2i((X509 *) srv_crt, NID_subject_alt_name, NULL, NULL);
        if (subject_alt_names != NULL) {

            // Check each name within the extension
            subject_alt_names_nb = sk_GENERAL_NAME_num(subject_alt_names);
            for (san_counter=0; san_counter<subject_alt_names_nb; san_counter++) {
                const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(subject_alt_names, san_counter);
                if (current_name->type == GEN_DNS) {
                    // Current name is a DNS name, let's check it, it's ASCII
                    if (ssl_match_domain_name(server, (const char *)current_name->d.dNSName->data)) {
                        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: found SAN '%s' - MATCH\n", __FILE__, current_name->d.dNSName->data);
                        match_result = TRUE; /* break; */
                    } else {
                        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: found SAN '%s'\n", __FILE__, current_name->d.dNSName->data);
                    }
                }
            }

        }

        sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free);
    }

    if (!match_result) {
        if (base->func (ssl,
                        LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            retval = FALSE;
        }
    }

    g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
           "%s:\n\tIssuer: %s\n\tSubject: %s\n\tFor: %s\n",
           __FILE__,
           X509_NAME_oneline(X509_get_issuer_name(srv_crt), NULL, 0),
           X509_NAME_oneline(X509_get_subject_name(srv_crt), NULL, 0),
           cn);

    g_free(cn);

    return retval;
}