Blame lib/mpi.c

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