|
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 |
}
|