static int ubsec_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
			const BIGNUM *q, const BIGNUM *dp,
			const BIGNUM *dq, const BIGNUM *qinv, BN_CTX *ctx)
	{
	int	y_len,
		m_len,
		fd;

	m_len = BN_num_bytes(p) + BN_num_bytes(q) + 1;
	y_len = BN_num_bits(p) + BN_num_bits(q);

	/* Check if hardware can't handle this argument. */
	if (y_len > max_key_len) {
		UBSECerr(UBSEC_F_UBSEC_MOD_EXP, UBSEC_R_SIZE_TOO_LARGE_OR_TOO_SMALL);
		return FAIL_TO_SOFTWARE;
	} 

	if (!bn_wexpand(r, p->top + q->top + 1)) {
		UBSECerr(UBSEC_F_UBSEC_RSA_MOD_EXP_CRT, UBSEC_R_BN_EXPAND_FAIL);
		return 0;
	}

	if ((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) <= 0) {
		fd = 0;
		UBSECerr(UBSEC_F_UBSEC_INIT, UBSEC_R_UNIT_FAILURE);
		return FAIL_TO_SOFTWARE;
	}

	if (p_UBSEC_rsa_mod_exp_crt_ioctl(fd,
		(unsigned char *)a->d, BN_num_bits(a), 
		(unsigned char *)qinv->d, BN_num_bits(qinv),
		(unsigned char *)dp->d, BN_num_bits(dp),
		(unsigned char *)p->d, BN_num_bits(p),
		(unsigned char *)dq->d, BN_num_bits(dq),
		(unsigned char *)q->d, BN_num_bits(q),
		(unsigned char *)r->d,  &y_len) != 0) {
		UBSECerr(UBSEC_F_UBSEC_MOD_EXP, UBSEC_R_REQUEST_FAILED);
                p_UBSEC_ubsec_close(fd);
		return FAIL_TO_SOFTWARE;
	}

	p_UBSEC_ubsec_close(fd);

	r->top = (BN_num_bits(p) + BN_num_bits(q) + BN_BITS2 - 1)/BN_BITS2;
	return 1;
}