Blame lib/mpi.c

Packit 549fdc
/*
Packit 549fdc
 * Copyright (C) 2001-2012 Free Software Foundation, Inc.
Packit 549fdc
 *
Packit 549fdc
 * Author: Nikos Mavrogiannopoulos
Packit 549fdc
 *
Packit 549fdc
 * This file is part of GnuTLS.
Packit 549fdc
 *
Packit 549fdc
 * The GnuTLS is free software; you can redistribute it and/or
Packit 549fdc
 * modify it under the terms of the GNU Lesser General Public License
Packit 549fdc
 * as published by the Free Software Foundation; either version 2.1 of
Packit 549fdc
 * the License, or (at your option) any later version.
Packit 549fdc
 *
Packit 549fdc
 * This library is distributed in the hope that it will be useful, but
Packit 549fdc
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 549fdc
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 549fdc
 * Lesser General Public License for more details.
Packit 549fdc
 *
Packit 549fdc
 * You should have received a copy of the GNU Lesser General Public License
Packit 549fdc
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
Packit 549fdc
 *
Packit 549fdc
 */
Packit 549fdc
Packit 549fdc
/* Here lie everything that has to do with large numbers, libgcrypt and
Packit 549fdc
 * other stuff that didn't fit anywhere else.
Packit 549fdc
 */
Packit 549fdc
Packit 549fdc
#include "gnutls_int.h"
Packit 549fdc
#include <libtasn1.h>
Packit 549fdc
#include "errors.h"
Packit 549fdc
#include <num.h>
Packit 549fdc
#include <mpi.h>
Packit 549fdc
#include <random.h>
Packit 549fdc
#include <x509/x509_int.h>
Packit 549fdc
Packit 549fdc
/* Functions that refer to the mpi library.
Packit 549fdc
 */
Packit 549fdc
Packit 549fdc
/* Returns a random number r, 0 < r < p */
Packit 549fdc
bigint_t
Packit 549fdc
_gnutls_mpi_random_modp(bigint_t r, bigint_t p,
Packit 549fdc
		      gnutls_rnd_level_t level)
Packit 549fdc
{
Packit 549fdc
	size_t size;
Packit 549fdc
	int ret;
Packit 549fdc
	bigint_t tmp;
Packit 549fdc
	uint8_t tmpbuf[512];
Packit 549fdc
	uint8_t *buf;
Packit 549fdc
	int buf_release = 0;
Packit 549fdc
	
Packit 549fdc
	size = ((_gnutls_mpi_get_nbits(p)+64)/8) + 1;
Packit 549fdc
Packit 549fdc
	if (size < sizeof(tmpbuf)) {
Packit 549fdc
		buf = tmpbuf;
Packit 549fdc
	} else {
Packit 549fdc
		buf = gnutls_malloc(size);
Packit 549fdc
		if (buf == NULL) {
Packit 549fdc
			gnutls_assert();
Packit 549fdc
			goto cleanup;
Packit 549fdc
		}
Packit 549fdc
		buf_release = 1;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	ret = gnutls_rnd(level, buf, size);
Packit 549fdc
	if (ret < 0) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		goto cleanup;
Packit 549fdc
	}
Packit 549fdc
	
Packit 549fdc
	ret = _gnutls_mpi_init_scan(&tmp, buf, size);
Packit 549fdc
	if (ret < 0) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		goto cleanup;
Packit 549fdc
	}
Packit 549fdc
	
Packit 549fdc
	ret = _gnutls_mpi_modm(tmp, tmp, p);
Packit 549fdc
	if (ret < 0) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		goto cleanup;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (_gnutls_mpi_cmp_ui(tmp, 0) == 0) {
Packit 549fdc
		ret = _gnutls_mpi_add_ui(tmp, tmp, 1);
Packit 549fdc
		if (ret < 0) {
Packit 549fdc
			gnutls_assert();
Packit 549fdc
			goto cleanup;
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (buf_release != 0) {
Packit 549fdc
		gnutls_free(buf);
Packit 549fdc
		buf = NULL;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (r != NULL) {
Packit 549fdc
		ret = _gnutls_mpi_set(r, tmp);
Packit 549fdc
		if (ret < 0)
Packit 549fdc
			goto cleanup;
Packit 549fdc
Packit 549fdc
		_gnutls_mpi_release(&tmp);
Packit 549fdc
		return r;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	return tmp;
Packit 549fdc
Packit 549fdc
      cleanup:
Packit 549fdc
	if (buf_release != 0)
Packit 549fdc
		gnutls_free(buf);
Packit 549fdc
	return NULL;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/* returns %GNUTLS_E_SUCCESS (0) on success
Packit 549fdc
 */
Packit 549fdc
int _gnutls_mpi_init_scan(bigint_t * ret_mpi, const void *buffer, size_t nbytes)
Packit 549fdc
{
Packit 549fdc
bigint_t r;
Packit 549fdc
int ret;
Packit 549fdc
Packit 549fdc
	ret = _gnutls_mpi_init(&r);
Packit 549fdc
	if (ret < 0)
Packit 549fdc
		return gnutls_assert_val(ret);
Packit 549fdc
Packit 549fdc
	ret =
Packit 549fdc
	    _gnutls_mpi_scan(r, buffer, nbytes);
Packit 549fdc
	if (ret < 0) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		_gnutls_mpi_release(&r);
Packit 549fdc
		return ret;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	*ret_mpi = r;
Packit 549fdc
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/* returns %GNUTLS_E_SUCCESS (0) on success. Fails if the number is zero.
Packit 549fdc
 */
Packit 549fdc
int
Packit 549fdc
_gnutls_mpi_init_scan_nz(bigint_t * ret_mpi, const void *buffer, size_t nbytes)
Packit 549fdc
{
Packit 549fdc
	int ret;
Packit 549fdc
Packit 549fdc
	ret = _gnutls_mpi_init_scan(ret_mpi, buffer, nbytes);
Packit 549fdc
	if (ret < 0)
Packit 549fdc
		return ret;
Packit 549fdc
Packit 549fdc
	/* MPIs with 0 bits are illegal
Packit 549fdc
	 */
Packit 549fdc
	if (_gnutls_mpi_cmp_ui(*ret_mpi, 0) == 0) {
Packit 549fdc
		_gnutls_mpi_release(ret_mpi);
Packit 549fdc
		return GNUTLS_E_MPI_SCAN_FAILED;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/* Always has the first bit zero */
Packit 549fdc
int _gnutls_mpi_dprint_lz(const bigint_t a, gnutls_datum_t * dest)
Packit 549fdc
{
Packit 549fdc
	int ret;
Packit 549fdc
	uint8_t *buf = NULL;
Packit 549fdc
	size_t bytes = 0;
Packit 549fdc
Packit 549fdc
	if (dest == NULL || a == NULL)
Packit 549fdc
		return GNUTLS_E_INVALID_REQUEST;
Packit 549fdc
Packit 549fdc
	_gnutls_mpi_print_lz(a, NULL, &bytes);
Packit 549fdc
Packit 549fdc
	if (bytes != 0)
Packit 549fdc
		buf = gnutls_malloc(bytes);
Packit 549fdc
	if (buf == NULL)
Packit 549fdc
		return GNUTLS_E_MEMORY_ERROR;
Packit 549fdc
Packit 549fdc
	ret = _gnutls_mpi_print_lz(a, buf, &bytes);
Packit 549fdc
	if (ret < 0) {
Packit 549fdc
		gnutls_free(buf);
Packit 549fdc
		return ret;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	dest->data = buf;
Packit 549fdc
	dest->size = bytes;
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
int _gnutls_mpi_dprint(const bigint_t a, gnutls_datum_t * dest)
Packit 549fdc
{
Packit 549fdc
	int ret;
Packit 549fdc
	uint8_t *buf = NULL;
Packit 549fdc
	size_t bytes = 0;
Packit 549fdc
Packit 549fdc
	if (dest == NULL || a == NULL)
Packit 549fdc
		return GNUTLS_E_INVALID_REQUEST;
Packit 549fdc
Packit 549fdc
	_gnutls_mpi_print(a, NULL, &bytes);
Packit 549fdc
	if (bytes != 0)
Packit 549fdc
		buf = gnutls_malloc(bytes);
Packit 549fdc
	if (buf == NULL)
Packit 549fdc
		return GNUTLS_E_MEMORY_ERROR;
Packit 549fdc
Packit 549fdc
	ret = _gnutls_mpi_print(a, buf, &bytes);
Packit 549fdc
	if (ret < 0) {
Packit 549fdc
		gnutls_free(buf);
Packit 549fdc
		return ret;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	dest->data = buf;
Packit 549fdc
	dest->size = bytes;
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/* This function will copy the mpi data into a datum,
Packit 549fdc
 * but will set minimum size to 'size'. That means that
Packit 549fdc
 * the output value is left padded with zeros.
Packit 549fdc
 */
Packit 549fdc
int
Packit 549fdc
_gnutls_mpi_dprint_size(const bigint_t a, gnutls_datum_t * dest,
Packit 549fdc
			size_t size)
Packit 549fdc
{
Packit 549fdc
	int ret;
Packit 549fdc
	uint8_t *buf = NULL;
Packit 549fdc
	size_t bytes = 0;
Packit 549fdc
	unsigned int i;
Packit 549fdc
Packit 549fdc
	if (dest == NULL || a == NULL)
Packit 549fdc
		return GNUTLS_E_INVALID_REQUEST;
Packit 549fdc
Packit 549fdc
	_gnutls_mpi_print(a, NULL, &bytes);
Packit 549fdc
	if (bytes != 0)
Packit 549fdc
		buf = gnutls_malloc(MAX(size, bytes));
Packit 549fdc
	if (buf == NULL)
Packit 549fdc
		return GNUTLS_E_MEMORY_ERROR;
Packit 549fdc
Packit 549fdc
	if (bytes <= size) {
Packit 549fdc
		size_t diff = size - bytes;
Packit 549fdc
		for (i = 0; i < diff; i++)
Packit 549fdc
			buf[i] = 0;
Packit 549fdc
		ret = _gnutls_mpi_print(a, &buf[diff], &bytes);
Packit 549fdc
	} else {
Packit 549fdc
		ret = _gnutls_mpi_print(a, buf, &bytes);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (ret < 0) {
Packit 549fdc
		gnutls_free(buf);
Packit 549fdc
		return ret;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	dest->data = buf;
Packit 549fdc
	dest->size = MAX(size, bytes);
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/* this function reads an integer
Packit 549fdc
 * from asn1 structs. Combines the read and mpi_scan
Packit 549fdc
 * steps.
Packit 549fdc
 */
Packit 549fdc
static int
Packit 549fdc
__gnutls_x509_read_int(ASN1_TYPE node, const char *value,
Packit 549fdc
		      bigint_t * ret_mpi, int overwrite)
Packit 549fdc
{
Packit 549fdc
	int result;
Packit 549fdc
	uint8_t *tmpstr = NULL;
Packit 549fdc
	int tmpstr_size;
Packit 549fdc
Packit 549fdc
	tmpstr_size = 0;
Packit 549fdc
	result = asn1_read_value(node, value, NULL, &tmpstr_size);
Packit 549fdc
	if (result != ASN1_MEM_ERROR) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		return _gnutls_asn2err(result);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	tmpstr = gnutls_malloc(tmpstr_size);
Packit 549fdc
	if (tmpstr == NULL) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		return GNUTLS_E_MEMORY_ERROR;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	result = asn1_read_value(node, value, tmpstr, &tmpstr_size);
Packit 549fdc
	if (result != ASN1_SUCCESS) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		gnutls_free(tmpstr);
Packit 549fdc
		return _gnutls_asn2err(result);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	result = _gnutls_mpi_init_scan(ret_mpi, tmpstr, tmpstr_size);
Packit 549fdc
Packit 549fdc
	if (overwrite)
Packit 549fdc
		zeroize_key(tmpstr, tmpstr_size);
Packit 549fdc
	gnutls_free(tmpstr);
Packit 549fdc
Packit 549fdc
	if (result < 0) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		return result;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
int
Packit 549fdc
_gnutls_x509_read_int(ASN1_TYPE node, const char *value,
Packit 549fdc
		      bigint_t * ret_mpi)
Packit 549fdc
{
Packit 549fdc
	return __gnutls_x509_read_int(node, value, ret_mpi, 0);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
int
Packit 549fdc
_gnutls_x509_read_key_int(ASN1_TYPE node, const char *value,
Packit 549fdc
		      bigint_t * ret_mpi)
Packit 549fdc
{
Packit 549fdc
	return __gnutls_x509_read_int(node, value, ret_mpi, 1);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/* Writes the specified integer into the specified node.
Packit 549fdc
 */
Packit 549fdc
static int
Packit 549fdc
__gnutls_x509_write_int(ASN1_TYPE node, const char *value, bigint_t mpi,
Packit 549fdc
		       int lz, int overwrite)
Packit 549fdc
{
Packit 549fdc
	uint8_t *tmpstr;
Packit 549fdc
	size_t s_len;
Packit 549fdc
	int result;
Packit 549fdc
Packit 549fdc
	s_len = 0;
Packit 549fdc
	if (lz)
Packit 549fdc
		result = _gnutls_mpi_print_lz(mpi, NULL, &s_len);
Packit 549fdc
	else
Packit 549fdc
		result = _gnutls_mpi_print(mpi, NULL, &s_len);
Packit 549fdc
Packit 549fdc
	if (result != GNUTLS_E_SHORT_MEMORY_BUFFER) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		return result;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	tmpstr = gnutls_malloc(s_len);
Packit 549fdc
	if (tmpstr == NULL) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		return GNUTLS_E_MEMORY_ERROR;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (lz)
Packit 549fdc
		result = _gnutls_mpi_print_lz(mpi, tmpstr, &s_len);
Packit 549fdc
	else
Packit 549fdc
		result = _gnutls_mpi_print(mpi, tmpstr, &s_len);
Packit 549fdc
Packit 549fdc
	if (result != 0) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		gnutls_free(tmpstr);
Packit 549fdc
		return GNUTLS_E_MPI_PRINT_FAILED;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	result = asn1_write_value(node, value, tmpstr, s_len);
Packit 549fdc
	
Packit 549fdc
	if (overwrite)
Packit 549fdc
		zeroize_key(tmpstr, s_len);
Packit 549fdc
Packit 549fdc
	gnutls_free(tmpstr);
Packit 549fdc
Packit 549fdc
	if (result != ASN1_SUCCESS) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		return _gnutls_asn2err(result);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
int
Packit 549fdc
_gnutls_x509_write_int(ASN1_TYPE node, const char *value, bigint_t mpi,
Packit 549fdc
		       int lz)
Packit 549fdc
{
Packit 549fdc
	return __gnutls_x509_write_int(node, value, mpi, lz, 0);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
int
Packit 549fdc
_gnutls_x509_write_key_int(ASN1_TYPE node, const char *value, bigint_t mpi,
Packit 549fdc
		       int lz)
Packit 549fdc
{
Packit 549fdc
	return __gnutls_x509_write_int(node, value, mpi, lz, 1);
Packit 549fdc
}