Exemplo n.º 1
0
int sxi_hashop_end(sxi_hashop_t *hashop)
{
    int rc = 0;
    if (!hashop || !hashop->conns)
	return -1;
    rc = sxi_hashop_batch_flush(hashop);
    while (hashop->finished != hashop->queries && !sxi_curlev_poll(sxi_conns_get_curlev(hashop->conns))) {
/*        syslog(LOG_INFO,"finished: %d, queries: %d", hashop->finished,
 *        hashop->queries);*/
    }
    if (hashop->finished > hashop->ok + hashop->enoent) {
	/* TODO: overwrite error msg or not? */
	sxi_seterr(sxi_conns_get_client(hashop->conns), SXE_ECOMM, "%d failed HEAD requests",
		   hashop->finished - hashop->ok - hashop->enoent);
	return -1;
    } else if (hashop->finished != hashop->queries) {
	sxi_seterr(sxi_conns_get_client(hashop->conns), SXE_ECOMM, "%d unfinished HEAD requests",
		   hashop->queries - hashop->finished);
	return -1;
    }
    if (hashop->cb_fail) {
	sxi_seterr(sxi_conns_get_client(hashop->conns), SXE_ECOMM, "%d callback failures",
		   hashop->cb_fail);
	return -1;
    }
    if (hashop->enoent) {
        sxc_client_t *sx = sxi_conns_get_client(hashop->conns);
        SXDEBUG("enoent: %d", hashop->enoent);
	return ENOENT;
    }
    if (!rc)
        sxc_clearerr(sxi_conns_get_client(hashop->conns));
    return rc;
}
Exemplo n.º 2
0
int sxi_filter_add_cfg(struct filter_handle *fh, const char *volname, const void *cfg, unsigned int cfg_len)
{
    struct filter_cfg *newcfg;
    if(!fh || !volname || !cfg || !cfg_len)
	return -1;

    if(filter_get_cfg(fh, volname))
	return 0;

    newcfg = malloc(sizeof(struct filter_cfg));
    if(!newcfg) {
	sxi_seterr(fh->sx, SXE_EMEM, "OOM");
	return -1;
    }
    newcfg->volname = strdup(volname);
    if(!newcfg->volname) {
	free(newcfg);
	sxi_seterr(fh->sx, SXE_EMEM, "OOM");
	return -1;
    }
    newcfg->cfg = malloc(cfg_len);
    if(!newcfg->cfg) {
	free(newcfg->volname);
	free(newcfg);
	sxi_seterr(fh->sx, SXE_EMEM, "OOM");
	return -1;
    }
    memcpy(newcfg->cfg, cfg, cfg_len);
    newcfg->cfg_len = cfg_len;
    newcfg->next = fh->cfg;
    fh->cfg = newcfg;
    return 0;
}
Exemplo n.º 3
0
Arquivo: nss.c Projeto: flashfoxter/sx
static CERTCertificate *load_cert_file(sxc_client_t *sx, const char *file, struct PK11_ctx *ctx) {
    const char *slot_name = "PEM Token #0";
    CK_OBJECT_CLASS obj_class;
    CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
    unsigned attr_cnt = 0;
    CK_BBOOL cktrue = CK_TRUE;
    SECMODModule *mod;
    CERTCertificate *cert = NULL;

    if(!file || !ctx) {
        sxi_seterr(sx, SXE_EARG, "NULL argument");
        return NULL;
    }
    memset(ctx, 0, sizeof(*ctx));

    mod = SECMOD_LoadUserModule("library=libnsspem.so name=PEM", NULL, PR_FALSE);
    if (!mod || !mod->loaded) {
        if (mod)
            SECMOD_DestroyModule(mod);
        sxi_setsyserr(sx, SXE_ECFG, "Failed to load NSS PEM library");
        return NULL;
    }

    sxi_crypto_check_ver(NULL);
    ctx->slot = PK11_FindSlotByName(slot_name);
    if (ctx->slot) {
        obj_class = CKO_CERTIFICATE;
        PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
        PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
        PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)file,
                      strlen(file) + 1);

        if(CKO_CERTIFICATE == obj_class) {
            CK_BBOOL *pval = &cktrue;
            PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
        }

        ctx->obj = PK11_CreateGenericObject(ctx->slot, attrs, attr_cnt, PR_FALSE);
        if (!ctx->obj) {
            sxi_seterr(sx, SXE_ECFG, "Cannot load certificate from '%s': %s, %s",
                       file, PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT),
                       PR_ErrorToName(PR_GetError()));
            return NULL;
        }
        ctx->list = PK11_ListCertsInSlot(ctx->slot);
        if (ctx->list) {
            CERTCertListNode *node = CERT_LIST_HEAD(ctx->list);
            cert = node ? node->cert : NULL;
        }
    } else {
        sxi_seterr(sx, SXE_ECFG, "Failed to initialize NSS PEM token");
        return NULL;
    }

    return cert;
}
Exemplo n.º 4
0
Arquivo: libsx.c Projeto: michals/sx
void sxi_setsyserr(sxc_client_t *sx, enum sxc_error_t err, const char *fmt, ...) {
    va_list ap;

    if(!sx)
	return;
    sxi_fmt_start(&sx->log.fmt);
    va_start(ap, fmt);
    sxi_vfmt_syserr(&sx->log.fmt, fmt, ap);
    va_end(ap);

    sxi_seterr(sx, err, "%s", sx->log.fmt.buf);
}
Exemplo n.º 5
0
int sxi_hashop_batch_add(sxi_hashop_t *hashop, const char *host, unsigned idx, const unsigned char *binhash, unsigned int blocksize)
{
    unsigned hidx;
    int rc = 0;
    sxc_client_t *sx;
    if (!hashop)
        return -1;
    if (hashop->kind == HASHOP_SKIP)
        return 0;
    sx = sxi_conns_get_client(hashop->conns);
    if (!host || !binhash) {
        sxi_seterr(sx, SXE_EARG, "Null arg to hashop_batch_add");
        return -1;
    }
    if ((hashop->current_host && strcmp(host, hashop->current_host)) || blocksize != hashop->current_blocksize || hashop->hashes_count >= DOWNLOAD_MAX_BLOCKS) {
        rc = sxi_hashop_batch_flush(hashop);
    }
    hashop->current_host = host;
    hashop->current_blocksize = blocksize;
    hidx = hashop->hashes_count * SXI_SHA1_TEXT_LEN;
    if (hashop->hashes_pos + SXI_SHA1_TEXT_LEN + 1 >= sizeof(hashop->hashes) ||
        hidx + SXI_SHA1_TEXT_LEN >= sizeof(hashop->hexhashes)) {
        sxi_seterr(sx, SXE_EARG, "Out of bounds hashes_pos: %u (limit %lu), hidx: %u (limit %lu)",
                   hashop->hashes_pos, (long)sizeof(hashop->hashes),
                   hidx, (long)sizeof(hashop->hexhashes));
        return -1;
    }
    sxi_bin2hex(binhash, SXI_SHA1_BIN_LEN, hashop->hashes + hashop->hashes_pos);
    memcpy(hashop->hexhashes + hidx, hashop->hashes + hashop->hashes_pos, SXI_SHA1_TEXT_LEN);
    SXDEBUG("hash @%d (%d): %.*s", idx, hashop->hashes_count, SXI_SHA1_TEXT_LEN, hashop->hashes + hashop->hashes_pos);
    hashop->hashes_pos += SXI_SHA1_TEXT_LEN;
    hashop->hashes[hashop->hashes_pos++] = ',';
    hashop->idxs_tmp[hashop->hashes_count] = idx;
    hashop->hashes_count++;
    SXDEBUG("returning: %d", rc);
    return rc;
}
Exemplo n.º 6
0
struct filter_handle *sxi_filter_gethandle(sxc_client_t *sx, const uint8_t *uuid)
{
    struct filter_ctx *fctx;
    int i;

    fctx = sxi_get_fctx(sx);
    if(!fctx || fctx->filter_cnt <= 0) {
	SXDEBUG("No filters available");
	sxi_seterr(sx, SXE_EFILTER, "No filters available");
	return NULL;
    }

    for(i = 0; i < fctx->filter_cnt; i++)
	if(!memcmp(fctx->filters[i].uuid_bin, uuid, 16))
	    return &fctx->filters[i];

    return NULL;
}
Exemplo n.º 7
0
Arquivo: nss.c Projeto: flashfoxter/sx
int sxi_sslctxfun(sxc_client_t *sx, curlev_t *ev, const struct curl_tlssessioninfo *info)
{
    CERTCertificate *cert;
    int rc = cert_from_sessioninfo(sx, info, &cert);
    if (rc)
        return rc;
    sxi_conns_t *conns = sxi_curlev_get_conns(ev);
    const char *hostname = sxi_conns_get_sslname(conns);
    SECStatus ret = CERT_VerifyCertName(cert, hostname);
    if (ret == SECSuccess) {
        sxi_curlev_set_verified(ev, 1);
    } else {
        PRInt32 err = PR_GetError();
        sxi_seterr(sx, SXE_ECOMM, "Certificate is not valid for cluster '%s': %s", hostname,
                   PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
        sxi_curlev_set_verified(ev, -1);
        return -1;
    }
    return 0;
}
Exemplo n.º 8
0
Arquivo: nss.c Projeto: flashfoxter/sx
static int cert_from_sessioninfo(sxc_client_t *sx, const struct curl_tlssessioninfo *info, CERTCertificate **cert)
{
    if (info->backend != CURLSSLBACKEND_NSS) {
        curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
        sxi_seterr(sx, SXE_ECURL, "SSL backend mismatch: NSS expected, got %d (curl %s)",
                   info->backend, data->ssl_version ? data->ssl_version : "N/A");
        return -1;
    }
    PRFileDesc *desc = info->internals;
    if(!desc) {
        SXDEBUG("NULL PRFileDesc context");
        return -EAGAIN;
    }
    *cert = SSL_PeerCertificate(desc);
    if (!*cert) {
        PRInt32 err = PR_GetError();
        SXDEBUG("Unable to retrieve certificate for cluster: %s",
                PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
        return -EAGAIN;
    }
    return 0;
}
Exemplo n.º 9
0
Arquivo: libsx.c Projeto: michals/sx
void sxi_setclusterr(sxc_client_t *sx, const char *nodeid, const char *reqid, int status,
                     const char *msg, const char *details)
{
    char httpcode[16];
    if (!sx)
        return;
    if (!*msg) {
        snprintf(httpcode, sizeof(httpcode), "HTTP code %d", status);
        msg = httpcode;
    }
    sxi_fmt_start(&sx->log.fmt);
    sxi_fmt_msg(&sx->log.fmt, "Failed to %s: %s (", sx->op ? sx->op : "query cluster", msg);
    if (sx->op_host) {
        sxi_fmt_msg(&sx->log.fmt, "sx://%s", sx->op_host);
        if (sx->op_vol) {
            sxi_fmt_msg(&sx->log.fmt, "/%s", sx->op_vol);
            if (sx->op_path) {
                sxi_fmt_msg(&sx->log.fmt, "/%s", sx->op_path);
            }
        }
    }
    sxi_fmt_msg(&sx->log.fmt," on");
    if (nodeid)
        sxi_fmt_msg(&sx->log.fmt, " node:%s", nodeid);
    if (reqid)
        sxi_fmt_msg(&sx->log.fmt, " reqid:%s", reqid);
    sxi_fmt_msg(&sx->log.fmt, ")");
    if (status < 400 || status >= 500) {
        /* do not print details on 40x */
        if (sx->verbose && details && *details) {
            sxi_fmt_msg(&sx->log.fmt, "\nHTTP %d: %s", status, details);
        }
    }
    sxi_seterr(sx, SXE_ECOMM, "%s", sx->log.fmt.buf);
    sxi_clear_operation(sx);
    SXDEBUG("Cluster query failed (HTTP %d): %s", status, sx->errbuf);
    if (details && *details)
        SXDEBUG("Cluster error: %s", details);
}
Exemplo n.º 10
0
Arquivo: nss.c Projeto: flashfoxter/sx
int sxi_vcrypt_get_cert_fingerprint(sxc_client_t *sx, const char *file, uint8_t *hash, unsigned int *len) {
    struct PK11_ctx ctx;
    CERTCertificate *cert = load_cert_file(sx, file, &ctx);

    if(!cert) {
        free_PK11_ctx(&ctx);
        return -1;
    }

    if(sxi_sha1_calc(NULL, 0, cert->derCert.data, cert->derCert.len, hash)) {
        sxi_seterr(sx, SXE_ECRYPT, "Failed to compute ca fingerprint");
        CERT_DestroyCertificate(cert);
        free_PK11_ctx(&ctx);
        return -1;
    }

    if(len)
        *len = SXI_SHA1_BIN_LEN;

    CERT_DestroyCertificate(cert);
    free_PK11_ctx(&ctx);
    return 0;
}
Exemplo n.º 11
0
static int filter_loadall(sxc_client_t *sx, const char *filter_dir)
{
    struct filter_ctx *fctx;
    DIR *dir;
    struct dirent *dent;
    struct stat sb;
    char *path;
    int ret = 0, pcnt = 0;

    if(!sx || !filter_dir)
	return 1;
    fctx = sxi_get_fctx(sx);

    if(fctx->filter_cnt == -1) {
	SXDEBUG("Filter subsystem not available");
	sxi_seterr(sx, SXE_EFILTER, "Filter subsystem not available");
	return 1;
    }

    if(!(dir = opendir(filter_dir))) {
	SXDEBUG("Can't open filter directory %s", filter_dir);
	sxi_seterr(sx, SXE_EFILTER, "Can't open filter directory %s", filter_dir);
	return 1;
    }

    while((dent = readdir(dir))) {
	if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
		unsigned int pathlen = strlen(filter_dir) + strlen(dent->d_name) + 2;
	    path = malloc(pathlen);
	    if(!path) {
		SXDEBUG("OOM allocating path");
		sxi_setsyserr(sx, SXE_EMEM, "OOM allocating path");
		closedir(dir);
		return 1;
	    }
	    snprintf(path, pathlen, "%s/%s", filter_dir, dent->d_name); /* FIXME: path separator */
	    if(lstat(path, &sb) == -1) {
		free(path);
		continue;
	    }

	    if(S_ISDIR(sb.st_mode)) {
		ret = filter_loadall(sx, path);
	    } else if(S_ISREG(sb.st_mode) && !strncmp(dent->d_name, "libsxf_", 7) && strstr(dent->d_name, ".so")) {
		ret = filter_register(sx, path);
		if(!ret)
		    pcnt++;
		else if(ret == 2)
		    ret = 0;
	    }
	    free(path);
	}
    }
    closedir(dir);

    if(!pcnt && ret) {
	sxi_seterr(sx, SXE_EFILTER, "No filters loaded due to version mismatch");
	return ret;
    }

    /*
    if(pcnt)
	SXDEBUG("Loaded %d filter(s) from %s", pcnt, filter_dir);
    */

    return 0;
}
Exemplo n.º 12
0
static int sxi_hashop_batch(sxi_hashop_t *hashop)
{
    const char *host, *hexhashes;
    unsigned int blocksize, i, n;
    sxi_query_t *query;
    int rc;
    if (!hashop || !hashop->conns)
	return -1;
    host = hashop->current_host;
    hexhashes = hashop->hexhashes;
    if (!host || !hexhashes)
        return -1;
    blocksize = hashop->current_blocksize;
    hashop->hashes[hashop->hashes_pos] = '\0';
    hashop->hexhashes[hashop->hashes_count*SXI_SHA1_TEXT_LEN] = '\0';
    sxc_client_t *sx;

    sx = sxi_conns_get_client(hashop->conns);
    if (hashop->finished > hashop->ok + hashop->enoent) {
	sxi_seterr(sx, SXE_ECOMM, "%d failed HEAD requests",
		   hashop->finished - hashop->ok - hashop->enoent);
	return -1;
    }
    struct hashop_ctx *pp = calloc(1, sizeof(*pp));
    if (!pp) {
        sxi_seterr(sx, SXE_EMEM, "failed to allocate presence parser");
        return -1;
    }
    memcpy(pp->idxs, hashop->idxs_tmp, sizeof(hashop->idxs_tmp));
    curlev_context_t *cbdata = sxi_cbdata_create_hashop(hashop->conns, batch_finish, pp);
    if (!cbdata) {
	sxi_seterr(sx, SXE_EMEM, "failed to allocate callback");
        free(pp);
	return -1;
    }
    pp->hexhashes = strdup(hexhashes);
    if (!pp->hexhashes) {
	sxi_seterr(sx, SXE_EMEM, "failed to allocate hashbatch");
        free(pp);
	free(cbdata);
	return -1;
    }
    pp->hashop = hashop;
    SXDEBUG("a->queries: %d", hashop->queries);
    hashop->queries += strlen(hexhashes) / 40;

    SXDEBUG("hashop %d, on %s, hexhashes: %s (%p)", hashop->hashes_count, hashop->hashes, hashop->hexhashes,
            hashop->hexhashes);
    n = strlen(hexhashes) / SXI_SHA1_TEXT_LEN;
    switch (hashop->kind) {
        case HASHOP_CHECK:
            query = sxi_hashop_proto_check(sxi_conns_get_client(hashop->conns), blocksize, hashop->hashes, hashop->hashes_pos);
            break;
        case HASHOP_RESERVE:
            query = sxi_hashop_proto_reserve(sxi_conns_get_client(hashop->conns), blocksize, hashop->hashes, hashop->hashes_pos, &hashop->global_vol_id, &hashop->reserve_id, &hashop->revision_id, hashop->replica, hashop->op_expires_at);
            break;
        case HASHOP_INUSE:
            query = sxi_hashop_proto_inuse_begin(sxi_conns_get_client(hashop->conns), hashop->has_reserve_id ? &hashop->reserve_id : NULL);
            for (i=0;i < n;i++) {
                block_meta_entry_t entry;
                block_meta_t meta;
                if (hex2bin(hexhashes + i * SXI_SHA1_TEXT_LEN, SXI_SHA1_TEXT_LEN, meta.hash.b, sizeof(meta.hash.b))) {
                    sxi_query_free(query);
                    query = NULL;
                    break;
                }
                memcpy(&entry.revision_id, &hashop->revision_id, sizeof(entry.revision_id));
                memcpy(&entry.global_vol_id, &hashop->global_vol_id, sizeof(entry.global_vol_id));
                entry.replica = hashop->replica;
                meta.entries = &entry;
                meta.count = 1;
                meta.blocksize = hashop->current_blocksize;
                query = sxi_hashop_proto_inuse_hash(sx, query, &meta);
            }
            query = sxi_hashop_proto_inuse_end(sx, query);
            break;
        default:
            query = NULL;
            break;
    }
    pp->query = query;
    if (query) {
        DEBUG("Sending query to %s", query->path);
        rc = sxi_cluster_query_ev(cbdata, hashop->conns, host, query->verb, query->path, query->content, query->content_len, presence_setup_cb, presence_cb);
    } else {
        free(pp->hexhashes);
        sxi_query_free(pp->query);
        free(pp);
        rc = -1;
    }
    sxi_cbdata_unref(&cbdata);
    return rc;
}
Exemplo n.º 13
0
Arquivo: cert.c Projeto: michals/sx
CURLcode sxi_verifyhost(sxc_client_t *sx, const char *hostname, X509 *server_cert)
{
    int matched = -1; /* -1 is no alternative match yet, 1 means match and 0
                         means mismatch */
    STACK_OF(GENERAL_NAME) *altnames;
    CURLcode res = CURLE_OK;

    /* get a "list" of alternative names */
    altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);

    if(altnames) {
        int numalts;
        int i;

        /* get amount of alternatives, RFC2459 claims there MUST be at least
           one, but we don't depend on it... */
        numalts = sk_GENERAL_NAME_num(altnames);

        /* loop through all alternatives while none has matched */
        for(i=0; (i<numalts) && (matched != 1); i++) {
            /* get a handle to alternative name number i */
            const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);

            /* only check alternatives of the same type the target is */
            if(check->type == GEN_DNS) {
                /* get data and length */
                const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
                size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);

                /* name/pattern comparison */
                /* The OpenSSL man page explicitly says: "In general it cannot be
                   assumed that the data returned by ASN1_STRING_data() is null
                   terminated or does not contain embedded nulls." But also that
                   "The actual format of the data will depend on the actual string
                   type itself: for example for and IA5String the data will be ASCII"

                   Curl uses strlen(altptr) == altlen here to check for embedded \0s.
                   We use memchr() to be safer from a possible non-null terminated string.
                   */
                if(!memchr(altptr, 0, altlen) &&
                   /* if this isn't true, there was an embedded zero in the name
                      string and we cannot match it. */
                   Curl_cert_hostcheck(altptr, hostname))
                    matched = 1;
                else
                    matched = 0;
            }
        }
        GENERAL_NAMES_free(altnames);
    }

    if(matched == 1)
        /* an alternative name matched the server hostname */
        SXDEBUG("\t subjectAltName: %s matched\n", hostname);
    else if(matched == 0) {
        /* an alternative name field existed, but didn't match and then
           we MUST fail */
        sxi_seterr(sx, SXE_ECOMM, "subjectAltName does not match %s\n", hostname);
        res = CURLE_PEER_FAILED_VERIFICATION;
    }
    else {
        /* we have to look to the last occurrence of a commonName in the
           distinguished one to get the most significant one. */
        int j,i=-1 ;

        /* The following is done because of a bug in 0.9.6b */

        unsigned char *nulstr = (unsigned char *)"";
        unsigned char *peer_CN = nulstr;

        X509_NAME *name = X509_get_subject_name(server_cert) ;
        if(name)
            while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i))>=0)
                i=j;

        /* we have the name entry and we will now convert this to a string
           that we can use for comparison. Doing this we support BMPstring,
           UTF8 etc. */

        if(i>=0) {
            ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i));

            /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
               is already UTF-8 encoded. We check for this case and copy the raw
               string manually to avoid the problem. This code can be made
               conditional in the future when OpenSSL has been fixed. Work-around
               brought by Alexis S. L. Carvalho. */
            if(tmp) {
                if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
                    j = ASN1_STRING_length(tmp);
                    if(j >= 0) {
                        peer_CN = OPENSSL_malloc(j+1);
                        if(peer_CN) {
                            memcpy(peer_CN, ASN1_STRING_data(tmp), j);
                            peer_CN[j] = '\0';
                        }
                    }
                }
                else /* not a UTF8 name */
                    j = ASN1_STRING_to_UTF8(&peer_CN, tmp);

                if(peer_CN && memchr(peer_CN, 0, j)) {
                    /* there was a terminating zero before the end of string, this
                       cannot match and we return failure! */
                    sxi_seterr(sx, SXE_ECOMM, "SSL: illegal cert name field");
                    res = CURLE_PEER_FAILED_VERIFICATION;
                }
            }
        }

        if(peer_CN == nulstr)
            peer_CN = NULL;
        /* curl would convert from UTF8 to host encoding if built with HAVE_ICONV (not default) */

        if(res)
            /* error already detected, pass through */
            ;
        else if(!peer_CN) {
            SXDEBUG("SSL: unable to obtain common name from peer certificate");
            res = CURLE_PEER_FAILED_VERIFICATION;
        }
        else if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) {
            sxi_seterr(sx, SXE_ECOMM, "SSL: certificate subject name '%s' does not match "
                    "target host name '%s'", peer_CN, hostname);
            res = CURLE_PEER_FAILED_VERIFICATION;
        }
        else {
            SXDEBUG("\t common name: %s (matched)\n", peer_CN);
        }
        if(peer_CN)
            OPENSSL_free(peer_CN);
    }
    return res;
}