Example #1
0
int
CA_set_key(const EAC_CTX *ctx,
        const unsigned char *priv, size_t priv_len,
        const unsigned char *pub, size_t pub_len)
{
    int r = 0;
    const unsigned char *p = priv;
    EVP_PKEY *key = NULL;

    check(ctx && ctx->ca_ctx && ctx->ca_ctx->ka_ctx,
            "Invalid arguments");

    /* always try d2i_AutoPrivateKey as priv may contain domain parameters */
    if (priv && d2i_AutoPrivateKey(&key, &p, priv_len)) {
        EVP_PKEY_free(ctx->ca_ctx->ka_ctx->key);
        ctx->ca_ctx->ka_ctx->key = key;
        if (pub) {
            /* it's OK if import of public key fails */
            EVP_PKEY_set_keys(key, NULL, 0, pub, pub_len, ctx->bn_ctx);
        }
    } else {
        /* wipe errors from d2i_AutoPrivateKey() */
        ERR_clear_error();
        check(EVP_PKEY_set_keys(ctx->ca_ctx->ka_ctx->key, priv, priv_len, pub,
                    pub_len, ctx->bn_ctx),
                "no valid keys given");
    }
    r = 1;

err:
    return r;
}
Example #2
0
static int test_d2i_AutoPrivateKey(const unsigned char *input,
                                   size_t input_len, int expected_id)
{
    int ret = 0;
    const unsigned char *p;
    EVP_PKEY *pkey = NULL;

    p = input;
    pkey = d2i_AutoPrivateKey(NULL, &p, input_len);
    if (pkey == NULL || p != input + input_len) {
        fprintf(stderr, "d2i_AutoPrivateKey failed\n");
        goto done;
    }

    if (EVP_PKEY_id(pkey) != expected_id) {
        fprintf(stderr, "Did not decode expected type\n");
        goto done;
    }

    ret = 1;

 done:
    if (!ret) {
        ERR_print_errors_fp(stderr);
    }

    EVP_PKEY_free(pkey);
    return ret;
}
Example #3
0
int
EAC_CTX_init_ta(const EAC_CTX *ctx,
           const unsigned char *privkey, size_t privkey_len,
           const unsigned char *cvca, size_t cvca_len)
{
    CVC_CERT *ta_cvca = NULL;
    int r = 0;

    check(ctx && ctx->ta_ctx, "Invalid arguments");

    if (privkey && privkey_len) {
        if (ctx->ta_ctx->priv_key)
            EVP_PKEY_free(ctx->ta_ctx->priv_key);
        ctx->ta_ctx->priv_key = d2i_AutoPrivateKey(&ctx->ta_ctx->priv_key,
                &privkey, privkey_len);
        if (!ctx->ta_ctx->priv_key)
            goto err;
    }

    if (cvca && cvca_len) {
        ta_cvca = CVC_d2i_CVC_CERT(&ta_cvca, &cvca, cvca_len);
    }
    r = TA_CTX_set_trust_anchor(ctx->ta_ctx, ta_cvca, ctx->bn_ctx);

err:
    if (ta_cvca)
        CVC_CERT_free(ta_cvca);

    return r;
}
Example #4
0
int mailstream_ssl_set_client_private_key_data(struct mailstream_ssl_context * ssl_context,
    unsigned char *pkey_der, size_t len)
{
#ifdef USE_SSL
#ifndef USE_GNUTLS
  EVP_PKEY *pkey = NULL;
  if (pkey_der != NULL && len > 0)
    pkey = d2i_AutoPrivateKey(NULL, (const unsigned char **)&pkey_der, len);
  ssl_context->client_pkey = (EVP_PKEY *)pkey;
  return 0;
#else
  gnutls_datum tmp;
  int r;
  ssl_context->client_pkey = NULL;
  if (len == 0)
    return 0;
  gnutls_x509_privkey_init(&(ssl_context->client_pkey));
  tmp.data = pkey_der;
  tmp.size = len;
  if ((r = gnutls_x509_privkey_import(ssl_context->client_pkey, &tmp, GNUTLS_X509_FMT_DER)) < 0) {
    gnutls_x509_privkey_deinit(ssl_context->client_pkey);
    ssl_context->client_pkey = NULL;
    return -1;
  }
  return 0;
#endif
#endif
  return -1;
}
Example #5
0
static int test_d2i_AutoPrivateKey(int i)
{
    int ret = 0;
    const unsigned char *p;
    EVP_PKEY *pkey = NULL;
    const APK_DATA *ak = &keydata[i];
    const unsigned char *input = ak->kder;
    size_t input_len = ak->size;
    int expected_id = ak->evptype;

    p = input;
    if (!TEST_ptr(pkey = d2i_AutoPrivateKey(NULL, &p, input_len))
            || !TEST_ptr_eq(p, input + input_len)
            || !TEST_int_eq(EVP_PKEY_id(pkey), expected_id))
        goto done;

    ret = 1;

 done:
    EVP_PKEY_free(pkey);
    return ret;
}
Example #6
0
static int
autoca_db_open(
	BackendDB *be,
	ConfigReply *cr
)
{
	slap_overinst *on = (slap_overinst *)be->bd_info;
	autoca_info *ai = on->on_bi.bi_private;

	Connection conn = { 0 };
	OperationBuffer opbuf;
	Operation *op;
	void *thrctx;
	Entry *e;
	Attribute *a;
	int rc;

	if (slapMode & SLAP_TOOL_MODE)
		return 0;

	if ( ! *aca_attr2[0].ad ) {
		int i, code;
		const char *text;

		for ( i=0; aca_attr2[i].at; i++ ) {
			code = slap_str2ad( aca_attr2[i].at, aca_attr2[i].ad, &text );
			if ( code ) return code;
		}

		/* Schema may not be loaded, ignore if missing */
		slap_str2ad( "ipHostNumber", &ad_ipaddr, &text );

		for ( i=0; aca_ocs[i].ot; i++ ) {
			code = register_oc( aca_ocs[i].ot, aca_ocs[i].oc, 0 );
			if ( code ) return code;
		}
	}

	thrctx = ldap_pvt_thread_pool_context();
	connection_fake_init2( &conn, &opbuf, thrctx, 0 );
	op = &opbuf.ob_op;
	op->o_bd = be;
	op->o_dn = be->be_rootdn;
	op->o_ndn = be->be_rootndn;
	rc = overlay_entry_get_ov( op, be->be_nsuffix, NULL, 
		NULL, 0, &e, on );

	if ( e ) {
		int gotoc = 0, gotat = 0;
		if ( is_entry_objectclass( e, oc_caObj, 0 )) {
			gotoc = 1;
			a = attr_find( e->e_attrs, ad_caPkey );
			if ( a ) {
				const unsigned char *pp;
				pp = (unsigned char *)a->a_vals[0].bv_val;
				ai->ai_pkey = d2i_AutoPrivateKey( NULL, &pp, a->a_vals[0].bv_len );
				if ( ai->ai_pkey )
				{
					a = attr_find( e->e_attrs, ad_caCert );
					if ( a )
					{
						pp = (unsigned char *)a->a_vals[0].bv_val;
						ai->ai_cert = d2i_X509( NULL, &pp, a->a_vals[0].bv_len );
						/* If TLS wasn't configured yet, set this as our CA */
						if ( !slap_tls_ctx )
							autoca_setca( a->a_vals );
					}
				}
				gotat = 1;
			}
		}
		overlay_entry_release_ov( op, e, 0, on );
		/* generate attrs, store... */
		if ( !gotat ) {
			genargs args;
			saveargs arg2;

			args.issuer_cert = NULL;
			args.issuer_pkey = NULL;
			args.subjectDN = &be->be_suffix[0];
			args.cert_exts = CAexts;
			args.more_exts = NULL;
			args.keybits = ai->ai_cakeybits;
			args.days = ai->ai_cadays;

			rc = autoca_gencert( op, &args );
			if ( rc )
				return -1;

			ai->ai_cert = args.newcert;
			ai->ai_pkey = args.newpkey;

			arg2.dn = be->be_suffix;
			arg2.ndn = be->be_nsuffix;
			arg2.isca = 1;
			if ( !gotoc )
				arg2.oc = oc_caObj;
			else
				arg2.oc = NULL;
			arg2.on = on;
			arg2.dercert = &args.dercert;
			arg2.derpkey = &args.derpkey;

			autoca_savecert( op, &arg2 );

			/* If TLS wasn't configured yet, set this as our CA */
			if ( !slap_tls_ctx )
				autoca_setca( &args.dercert );

			op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
			op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
		}
	}

	return 0;
}
Example #7
0
static int test_EVP_PKEY_check(int i)
{
    int ret = 0;
    const unsigned char *p;
    EVP_PKEY *pkey = NULL;
#ifndef OPENSSL_NO_EC
    EC_KEY *eckey = NULL;
#endif
    EVP_PKEY_CTX *ctx = NULL;
    EVP_PKEY_CTX *ctx2 = NULL;
    const APK_DATA *ak = &keycheckdata[i];
    const unsigned char *input = ak->kder;
    size_t input_len = ak->size;
    int expected_id = ak->evptype;
    int expected_check = ak->check;
    int expected_pub_check = ak->pub_check;
    int expected_param_check = ak->param_check;
    int type = ak->type;
    BIO *pubkey = NULL;

    p = input;

    switch (type) {
    case 0:
        if (!TEST_ptr(pkey = d2i_AutoPrivateKey(NULL, &p, input_len))
            || !TEST_ptr_eq(p, input + input_len)
            || !TEST_int_eq(EVP_PKEY_id(pkey), expected_id))
            goto done;
        break;
#ifndef OPENSSL_NO_EC
    case 1:
        if (!TEST_ptr(pubkey = BIO_new_mem_buf(input, input_len))
            || !TEST_ptr(eckey = d2i_EC_PUBKEY_bio(pubkey, NULL))
            || !TEST_ptr(pkey = EVP_PKEY_new())
            || !TEST_true(EVP_PKEY_assign_EC_KEY(pkey, eckey)))
            goto done;
        break;
    case 2:
        if (!TEST_ptr(eckey = d2i_ECParameters(NULL, &p, input_len))
            || !TEST_ptr_eq(p, input + input_len)
            || !TEST_ptr(pkey = EVP_PKEY_new())
            || !TEST_true(EVP_PKEY_assign_EC_KEY(pkey, eckey)))
            goto done;
        break;
#endif
    default:
        return 0;
    }

    if (!TEST_ptr(ctx = EVP_PKEY_CTX_new(pkey, NULL)))
        goto done;

    if (!TEST_int_eq(EVP_PKEY_check(ctx), expected_check))
        goto done;

    if (!TEST_int_eq(EVP_PKEY_public_check(ctx), expected_pub_check))
        goto done;

    if (!TEST_int_eq(EVP_PKEY_param_check(ctx), expected_param_check))
        goto done;

    ctx2 = EVP_PKEY_CTX_new_id(0xdefaced, NULL);
    /* assign the pkey directly, as an internal test */
    EVP_PKEY_up_ref(pkey);
    ctx2->pkey = pkey;

    if (!TEST_int_eq(EVP_PKEY_check(ctx2), 0xbeef))
        goto done;

    if (!TEST_int_eq(EVP_PKEY_public_check(ctx2), 0xbeef))
        goto done;

    if (!TEST_int_eq(EVP_PKEY_param_check(ctx2), 0xbeef))
        goto done;

    ret = 1;

 done:
    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_CTX_free(ctx2);
    EVP_PKEY_free(pkey);
    BIO_free(pubkey);
    return ret;
}
Example #8
0
/**
 * Esta función se encargará de producir, lo que para el SAT[1], es un sello
 * digital. Este sello digital consiste en el firmado digital del hash de un
 * string, que para los casos de un CFDi se trataría de la cadena original
 *
 * El usuario es responsable de liberar la memoria del resultado (con free())
 * [1]: http://www.sat.gob.mx
 */
unsigned char *
sello_alloc(const char *keyfile, const char *digest, const unsigned char *cadena, const int verbose)
{
  int read = 0;
  int len = 0;
  unsigned char *buffer = NULL;
  const unsigned char *tmp;
  unsigned char signbuffer[1024];
  unsigned int signlen = 0;
  char *data = NULL;
  FILE *file = NULL;
  BIO* err = NULL;
  EVP_MD_CTX mdctx;
  EVP_PKEY *privateKey = NULL;

  file = fopen(keyfile, "rb");
  if ( file == NULL ) {
    /* An error ocurred */
    if ( verbose ) {
      fprintf(stderr, "No fue posible leer correctamente el archivo %s.\n", keyfile);
    }
    return NULL;
  }
  len = fseek(file, 0, SEEK_END);
  if ( len ) {
    /* An error did occur */
    if ( verbose ) {
      fprintf(stderr, "No fue posible obtener el final del archivo %s.\n", keyfile);
    }
    fclose(file);
    return NULL;
  }
  len = ftell(file);
  rewind(file);


  buffer = (unsigned char *)calloc(len + 1, sizeof(unsigned char));
  read = fread(buffer, sizeof(unsigned char), len, file);
  fclose(file);
  if ( read != len ) {
    if ( verbose ) {
      fprintf(stderr, "An error has ocurred. The number of items read was %d, but it should be %d instead.\n", read, len);
      free(buffer);
    }
    return NULL;
  }

  /* Set the BIO method for the error messages */
  if ( err == NULL ) {
    if ( (err = BIO_new(BIO_s_file())) ) {
      BIO_set_fp(err, stderr, BIO_NOCLOSE|BIO_FP_TEXT);
    }
  }

  /* Now convert the bytes to a EVP_PKEY structure */
  tmp = buffer;
  privateKey = d2i_AutoPrivateKey(NULL, &tmp, len);
  if ( privateKey == NULL ) {
    if ( verbose ) {
      BIO_printf(err, "Error at reading the private key on %s.\n", keyfile);
      ERR_print_errors(err);
    }
    free(buffer);
    return NULL;
  }
  free(buffer);

  /* Add all digest algorithms to the table */
  OpenSSL_add_all_digests();

  /* Initialize the digest context */
  EVP_MD_CTX_init(&mdctx);
  if ( EVP_DigestInit_ex(&mdctx, EVP_get_digestbyname(digest), 0 ) == 0 ) {
    if ( verbose ) {
      BIO_printf(err, "Error at initializing the digest context to use '%s' as digest algorithm.\n", digest);
      ERR_print_errors(err);
    }
    EVP_PKEY_free(privateKey);
    EVP_cleanup();
    BIO_free(err);
    return NULL;
  }

  /* Sign up the data in the current context */
  if ( EVP_SignInit_ex(&mdctx, EVP_get_digestbyname(digest), 0) == 0 ) {
    if ( verbose ) {
      BIO_printf(err, "Error at setting up the signing context to use digest '%s'.\n", digest);
      ERR_print_errors(err);
    }
    EVP_PKEY_free(privateKey);
    EVP_cleanup();
    BIO_free(err);
    return NULL;
  }
  if ( EVP_SignUpdate(&mdctx, cadena, strlen((char *)cadena)) == 0 ) {
    if ( verbose ) {
      BIO_printf(err, "Error hashing the data into the signing context.\n");
      ERR_print_errors(err);
    }
    EVP_PKEY_free(privateKey);
    EVP_cleanup();
    BIO_free(err);
    return NULL;
  }

  signlen = sizeof(signbuffer);
  memset(signbuffer, 0, 1024);
  if ( EVP_SignFinal(&mdctx, signbuffer, (unsigned int* )&signlen, privateKey) == 0 ) {
    if ( verbose ) {
      BIO_printf(err, "Error signing the data in the context with the private key.\n");
      ERR_print_errors(err);
    }
    EVP_PKEY_free(privateKey);
    EVP_cleanup();
    BIO_free(err);
    return NULL;
  }

  EVP_MD_CTX_cleanup(&mdctx);
  EVP_PKEY_free(privateKey);
  EVP_cleanup();
  BIO_free(err);

  /* Now prepare the data to be base64 encoded */
  base64_encode_alloc((const char *)signbuffer, signlen, &data);

  return (unsigned char *)data;
}
Example #9
0
/*
 * initialize a new TLS context
 */
static int
tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
{
	tlso_ctx *ctx = (tlso_ctx *)lo->ldo_tls_ctx;
	int i;

	if ( is_server ) {
		SSL_CTX_set_session_id_context( ctx,
			(const unsigned char *) "OpenLDAP", sizeof("OpenLDAP")-1 );
	}

#ifdef SSL_OP_NO_TLSv1
#ifdef SSL_OP_NO_TLSv1_1
#ifdef SSL_OP_NO_TLSv1_2
	if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_2)
		SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
			SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 |
			SSL_OP_NO_TLSv1_2 );
	else
#endif
	if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_1)
		SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
			SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 );
	else
#endif
	if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_0)
		SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
			SSL_OP_NO_TLSv1);
	else
#endif
	if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL3 )
		SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 );
	else if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL2 )
		SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 );

	if ( lo->ldo_tls_ciphersuite &&
		!SSL_CTX_set_cipher_list( ctx, lt->lt_ciphersuite ) )
	{
		Debug( LDAP_DEBUG_ANY,
			   "TLS: could not set cipher list %s.\n",
			   lo->ldo_tls_ciphersuite, 0, 0 );
		tlso_report_error();
		return -1;
	}

	if ( lo->ldo_tls_cacertfile == NULL && lo->ldo_tls_cacertdir == NULL &&
		lo->ldo_tls_cacert.bv_val == NULL ) {
		if ( !SSL_CTX_set_default_verify_paths( ctx ) ) {
			Debug( LDAP_DEBUG_ANY, "TLS: "
				"could not use default certificate paths", 0, 0, 0 );
			tlso_report_error();
			return -1;
		}
	} else {
		X509 *cert = NULL;
		if ( lo->ldo_tls_cacert.bv_val ) {
			const unsigned char *pp = lo->ldo_tls_cacert.bv_val;
			cert = d2i_X509( NULL, &pp, lo->ldo_tls_cacert.bv_len );
			X509_STORE *store = SSL_CTX_get_cert_store( ctx );
			if ( !X509_STORE_add_cert( store, cert )) {
				Debug( LDAP_DEBUG_ANY, "TLS: "
					"could not use CA certificate", 0, 0, 0 );
				tlso_report_error();
				return -1;
			}
		}
		if (( lt->lt_cacertfile || lt->lt_cacertdir ) && !SSL_CTX_load_verify_locations( ctx,
				lt->lt_cacertfile, lt->lt_cacertdir ) )
		{
			Debug( LDAP_DEBUG_ANY, "TLS: "
				"could not load verify locations (file:`%s',dir:`%s').\n",
				lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "",
				lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "",
				0 );
			tlso_report_error();
			return -1;
		}

		if ( is_server ) {
			STACK_OF(X509_NAME) *calist;
			/* List of CA names to send to a client */
			calist = tlso_ca_list( lt->lt_cacertfile, lt->lt_cacertdir, cert );
			if ( !calist ) {
				Debug( LDAP_DEBUG_ANY, "TLS: "
					"could not load client CA list (file:`%s',dir:`%s').\n",
					lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "",
					lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "",
					0 );
				tlso_report_error();
				return -1;
			}

			SSL_CTX_set_client_CA_list( ctx, calist );
		}
		if ( cert )
			X509_free( cert );
	}

	if ( lo->ldo_tls_cert.bv_val )
	{
		const unsigned char *pp = lo->ldo_tls_cert.bv_val;
		X509 *cert = d2i_X509( NULL, &pp, lo->ldo_tls_cert.bv_len );
		if ( !SSL_CTX_use_certificate( ctx, cert )) {
			Debug( LDAP_DEBUG_ANY,
				"TLS: could not use certificate.\n", 0,0,0);
			tlso_report_error();
			return -1;
		}
		X509_free( cert );
	} else
	if ( lo->ldo_tls_certfile &&
		!SSL_CTX_use_certificate_file( ctx,
			lt->lt_certfile, SSL_FILETYPE_PEM ) )
	{
		Debug( LDAP_DEBUG_ANY,
			"TLS: could not use certificate file `%s'.\n",
			lo->ldo_tls_certfile,0,0);
		tlso_report_error();
		return -1;
	}

	/* Key validity is checked automatically if cert has already been set */
	if ( lo->ldo_tls_key.bv_val )
	{
		const unsigned char *pp = lo->ldo_tls_key.bv_val;
		EVP_PKEY *pkey = d2i_AutoPrivateKey( NULL, &pp, lo->ldo_tls_key.bv_len );
		if ( !SSL_CTX_use_PrivateKey( ctx, pkey ))
		{
			Debug( LDAP_DEBUG_ANY,
				"TLS: could not use private key.\n", 0,0,0);
			tlso_report_error();
			return -1;
		}
		EVP_PKEY_free( pkey );
	} else
	if ( lo->ldo_tls_keyfile &&
		!SSL_CTX_use_PrivateKey_file( ctx,
			lt->lt_keyfile, SSL_FILETYPE_PEM ) )
	{
		Debug( LDAP_DEBUG_ANY,
			"TLS: could not use key file `%s'.\n",
			lo->ldo_tls_keyfile,0,0);
		tlso_report_error();
		return -1;
	}

	if ( is_server && lo->ldo_tls_dhfile ) {
		DH *dh;
		BIO *bio;

		if (( bio=BIO_new_file( lt->lt_dhfile,"r" )) == NULL ) {
			Debug( LDAP_DEBUG_ANY,
				"TLS: could not use DH parameters file `%s'.\n",
				lo->ldo_tls_dhfile,0,0);
			tlso_report_error();
			return -1;
		}
		if (!( dh=PEM_read_bio_DHparams( bio, NULL, NULL, NULL ))) {
			Debug( LDAP_DEBUG_ANY,
				"TLS: could not read DH parameters file `%s'.\n",
				lo->ldo_tls_dhfile,0,0);
			tlso_report_error();
			BIO_free( bio );
			return -1;
		}
		BIO_free( bio );
		SSL_CTX_set_tmp_dh( ctx, dh );
		SSL_CTX_set_options( ctx, SSL_OP_SINGLE_DH_USE );
		DH_free( dh );
	}

	if ( is_server && lo->ldo_tls_ecname ) {
#ifdef OPENSSL_NO_EC
		Debug( LDAP_DEBUG_ANY,
			"TLS: Elliptic Curves not supported.\n", 0,0,0 );
		return -1;
#else
		EC_KEY *ecdh;

		int nid = OBJ_sn2nid( lt->lt_ecname );
		if ( nid == NID_undef ) {
			Debug( LDAP_DEBUG_ANY,
				"TLS: could not use EC name `%s'.\n",
				lo->ldo_tls_ecname,0,0);
			tlso_report_error();
			return -1;
		}
		ecdh = EC_KEY_new_by_curve_name( nid );
		if ( ecdh == NULL ) {
			Debug( LDAP_DEBUG_ANY,
				"TLS: could not generate key for EC name `%s'.\n",
				lo->ldo_tls_ecname,0,0);
			tlso_report_error();
			return -1;
		}
		SSL_CTX_set_tmp_ecdh( ctx, ecdh );
		SSL_CTX_set_options( ctx, SSL_OP_SINGLE_ECDH_USE );
		EC_KEY_free( ecdh );
#endif
	}

	if ( tlso_opt_trace ) {
		SSL_CTX_set_info_callback( ctx, tlso_info_cb );
	}

	i = SSL_VERIFY_NONE;
	if ( lo->ldo_tls_require_cert ) {
		i = SSL_VERIFY_PEER;
		if ( lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND ||
			 lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD ) {
			i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
		}
	}

	SSL_CTX_set_verify( ctx, i,
		lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_ALLOW ?
		tlso_verify_ok : tlso_verify_cb );
#if OPENSSL_VERSION_NUMBER < 0x10100000
	SSL_CTX_set_tmp_rsa_callback( ctx, tlso_tmp_rsa_cb );
#endif
#ifdef HAVE_OPENSSL_CRL
	if ( lo->ldo_tls_crlcheck ) {
		X509_STORE *x509_s = SSL_CTX_get_cert_store( ctx );
		if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_PEER ) {
			X509_STORE_set_flags( x509_s, X509_V_FLAG_CRL_CHECK );
		} else if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_ALL ) {
			X509_STORE_set_flags( x509_s, 
					X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL  );
		}
	}
#endif
	return 0;
}