Blame lib/auth/srp_sb64.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
#include "gnutls_int.h"
Packit aea12f
#include "errors.h"
Packit aea12f
#include <datum.h>
Packit aea12f
#include <auth/srp_passwd.h>
Packit aea12f
Packit aea12f
#ifdef ENABLE_SRP
Packit aea12f
Packit aea12f
/* this is a modified base64 for srp !!!
Packit aea12f
 * It seems that everybody makes their own base64 conversion.
Packit aea12f
 */
Packit aea12f
static const uint8_t b64table[] =
Packit aea12f
    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
Packit aea12f
Packit aea12f
static const uint8_t asciitable[128] = {
Packit aea12f
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit aea12f
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit aea12f
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit aea12f
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit aea12f
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit aea12f
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit aea12f
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit aea12f
	0xff, 0xff, 0xff, 0xff, 0x3e, 0x3f,
Packit aea12f
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
Packit aea12f
	0x06, 0x07, 0x08, 0x09, 0xff, 0xff,
Packit aea12f
	0xff, 0xff, 0xff, 0xff, 0xff, 0x0a,
Packit aea12f
	0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
Packit aea12f
	0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
Packit aea12f
	0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
Packit aea12f
	0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
Packit aea12f
	0x23, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit aea12f
	0xff, 0x24, 0x25, 0x26, 0x27, 0x28,
Packit aea12f
	0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
Packit aea12f
	0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
Packit aea12f
	0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
Packit aea12f
	0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff,
Packit aea12f
	0xff, 0xff
Packit aea12f
};
Packit aea12f
Packit aea12f
inline static int encode(uint8_t * result, const uint8_t * rdata, unsigned left)
Packit aea12f
{
Packit aea12f
Packit aea12f
	int data_len;
Packit aea12f
	int c, ret = 4;
Packit aea12f
	uint8_t data[3];
Packit aea12f
Packit aea12f
	if (left > 3)
Packit aea12f
		data_len = 3;
Packit aea12f
	else
Packit aea12f
		data_len = left;
Packit aea12f
Packit aea12f
	data[0] = data[1] = data[2] = 0;
Packit aea12f
	memcpy(data, rdata, data_len);
Packit aea12f
Packit aea12f
	switch (data_len) {
Packit aea12f
	case 3:
Packit aea12f
		result[0] = b64table[((data[0] & 0xfc) >> 2)];
Packit aea12f
		result[1] =
Packit aea12f
		    b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
Packit aea12f
			      ((data[1] & 0xf0) >> 4))];
Packit aea12f
		result[2] =
Packit aea12f
		    b64table[((((data[1] & 0x0f) << 2) & 0xff) |
Packit aea12f
			      ((data[2] & 0xc0) >> 6))];
Packit aea12f
		result[3] = b64table[(data[2] & 0x3f) & 0xff];
Packit aea12f
		break;
Packit aea12f
	case 2:
Packit aea12f
		if ((c = ((data[0] & 0xf0) >> 4)) != 0) {
Packit aea12f
			result[0] = b64table[c];
Packit aea12f
			result[1] =
Packit aea12f
			    b64table[((((data[0] & 0x0f) << 2) & 0xff) |
Packit aea12f
				      ((data[1] & 0xc0) >> 6))];
Packit aea12f
			result[2] = b64table[(data[1] & 0x3f) & 0xff];
Packit aea12f
			result[3] = '\0';
Packit aea12f
			ret -= 1;
Packit aea12f
		} else {
Packit aea12f
			if ((c =
Packit aea12f
			     ((data[0] & 0x0f) << 2) | ((data[1] & 0xc0) >>
Packit aea12f
							6)) != 0) {
Packit aea12f
				result[0] = b64table[c];
Packit aea12f
				result[1] = b64table[data[1] & 0x3f];
Packit aea12f
				result[2] = '\0';
Packit aea12f
				result[3] = '\0';
Packit aea12f
				ret -= 2;
Packit aea12f
			} else {
Packit aea12f
				result[0] = b64table[data[0] & 0x3f];
Packit aea12f
				result[1] = '\0';
Packit aea12f
				result[2] = '\0';
Packit aea12f
				result[3] = '\0';
Packit aea12f
				ret -= 3;
Packit aea12f
			}
Packit aea12f
		}
Packit aea12f
		break;
Packit aea12f
	case 1:
Packit aea12f
		if ((c = ((data[0] & 0xc0) >> 6)) != 0) {
Packit aea12f
			result[0] = b64table[c];
Packit aea12f
			result[1] = b64table[(data[0] & 0x3f) & 0xff];
Packit aea12f
			result[2] = '\0';
Packit aea12f
			result[3] = '\0';
Packit aea12f
			ret -= 2;
Packit aea12f
		} else {
Packit aea12f
			result[0] = b64table[(data[0] & 0x3f) & 0xff];
Packit aea12f
			result[1] = '\0';
Packit aea12f
			result[2] = '\0';
Packit aea12f
			result[3] = '\0';
Packit aea12f
			ret -= 3;
Packit aea12f
		}
Packit aea12f
		break;
Packit aea12f
	default:
Packit aea12f
		return GNUTLS_E_BASE64_ENCODING_ERROR;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return ret;
Packit aea12f
Packit aea12f
}
Packit aea12f
Packit aea12f
/* encodes data and puts the result into result (locally allocated)
Packit aea12f
 * The result_size is the return value
Packit aea12f
 */
Packit aea12f
static int
Packit aea12f
_gnutls_sbase64_encode(uint8_t * data, size_t data_size, char **result)
Packit aea12f
{
Packit aea12f
	unsigned i, j;
Packit aea12f
	int ret, tmp;
Packit aea12f
	uint8_t tmpres[4];
Packit aea12f
	unsigned mod = data_size % 3;
Packit aea12f
Packit aea12f
	ret = mod;
Packit aea12f
	if (ret != 0)
Packit aea12f
		ret = 4;
Packit aea12f
	else
Packit aea12f
		ret = 0;
Packit aea12f
Packit aea12f
	ret += (data_size * 4) / 3;
Packit aea12f
Packit aea12f
	(*result) = gnutls_calloc(1, ret + 1);
Packit aea12f
	if ((*result) == NULL)
Packit aea12f
		return GNUTLS_E_MEMORY_ERROR;
Packit aea12f
Packit aea12f
	i = j = 0;
Packit aea12f
/* encode the bytes that are not a multiple of 3 
Packit aea12f
 */
Packit aea12f
	if (mod > 0) {
Packit aea12f
		tmp = encode(tmpres, &data[0], mod);
Packit aea12f
		if (tmp < 0) {
Packit aea12f
			gnutls_free((*result));
Packit aea12f
			return tmp;
Packit aea12f
		}
Packit aea12f
Packit aea12f
		memcpy(&(*result)[0], tmpres, tmp);
Packit aea12f
		i = mod;
Packit aea12f
		j = tmp;
Packit aea12f
Packit aea12f
	}
Packit aea12f
/* encode the rest
Packit aea12f
 */
Packit aea12f
	for (; i < data_size; i += 3, j += 4) {
Packit aea12f
		tmp = encode(tmpres, &data[i], data_size - i);
Packit aea12f
		if (tmp < 0) {
Packit aea12f
			gnutls_free((*result));
Packit aea12f
			return tmp;
Packit aea12f
		}
Packit aea12f
		memcpy(&(*result)[j], tmpres, tmp);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return strlen(*result);
Packit aea12f
}
Packit aea12f
Packit aea12f
Packit aea12f
/* data must be 4 bytes
Packit aea12f
 * result should be 3 bytes
Packit aea12f
 */
Packit aea12f
#define TOASCII(c) (c < 127 ? asciitable[c] : 0xff)
Packit aea12f
inline static int decode(uint8_t * result, const uint8_t * data)
Packit aea12f
{
Packit aea12f
	uint8_t a1, a2;
Packit aea12f
	int ret = 3;
Packit aea12f
Packit aea12f
	memset(result, 0, 3);
Packit aea12f
Packit aea12f
	a1 = TOASCII(data[3]);
Packit aea12f
	a2 = TOASCII(data[2]);
Packit aea12f
	if (a1 != 0xff)
Packit aea12f
		result[2] = a1 & 0xff;
Packit aea12f
	else
Packit aea12f
		return GNUTLS_E_BASE64_DECODING_ERROR;
Packit aea12f
	if (a2 != 0xff)
Packit aea12f
		result[2] |= ((a2 & 0x03) << 6) & 0xff;
Packit aea12f
Packit aea12f
	a1 = a2;
Packit aea12f
	a2 = TOASCII(data[1]);
Packit aea12f
	if (a1 != 0xff)
Packit aea12f
		result[1] = ((a1 & 0x3c) >> 2);
Packit aea12f
	if (a2 != 0xff)
Packit aea12f
		result[1] |= ((a2 & 0x0f) << 4);
Packit aea12f
	else if (a1 == 0xff || result[1] == 0)
Packit aea12f
		ret--;
Packit aea12f
Packit aea12f
	a1 = a2;
Packit aea12f
	a2 = TOASCII(data[0]);
Packit aea12f
	if (a1 != 0xff)
Packit aea12f
		result[0] = (((a1 & 0x30) >> 4) & 0xff);
Packit aea12f
	if (a2 != 0xff)
Packit aea12f
		result[0] |= ((a2 << 2) & 0xff);
Packit aea12f
	else if (a1 == 0xff || result[0] == 0)
Packit aea12f
		ret--;
Packit aea12f
Packit aea12f
	return ret;
Packit aea12f
}
Packit aea12f
Packit aea12f
/* decodes data and puts the result into result (locally allocated)
Packit aea12f
 * The result_size is the return value.
Packit aea12f
 * That function does not ignore newlines tabs etc. You should remove them
Packit aea12f
 * before calling it.
Packit aea12f
 */
Packit aea12f
int
Packit aea12f
_gnutls_sbase64_decode(char *data, size_t idata_size, uint8_t ** result)
Packit aea12f
{
Packit aea12f
	unsigned i, j;
Packit aea12f
	int ret, left;
Packit aea12f
	int data_size, tmp;
Packit aea12f
	uint8_t datrev[4];
Packit aea12f
	uint8_t tmpres[3];
Packit aea12f
Packit aea12f
	data_size = (idata_size / 4) * 4;
Packit aea12f
	left = idata_size % 4;
Packit aea12f
Packit aea12f
	ret = (data_size / 4) * 3;
Packit aea12f
Packit aea12f
	if (left > 0)
Packit aea12f
		ret += 3;
Packit aea12f
Packit aea12f
	(*result) = gnutls_malloc(ret + 1);
Packit aea12f
	if ((*result) == NULL)
Packit aea12f
		return GNUTLS_E_MEMORY_ERROR;
Packit aea12f
Packit aea12f
	/* the first "block" is treated with special care */
Packit aea12f
	tmp = 0;
Packit aea12f
	if (left > 0) {
Packit aea12f
		memset(datrev, 0, 4);
Packit aea12f
		memcpy(&datrev[4 - left], data, left);
Packit aea12f
Packit aea12f
		tmp = decode(tmpres, datrev);
Packit aea12f
		if (tmp < 0) {
Packit aea12f
			gnutls_free((*result));
Packit aea12f
			return tmp;
Packit aea12f
		}
Packit aea12f
Packit aea12f
		memcpy(*result, &tmpres[3 - tmp], tmp);
Packit aea12f
		if (tmp < 3)
Packit aea12f
			ret -= (3 - tmp);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	/* rest data */
Packit aea12f
	for (i = left, j = tmp; i < idata_size; i += 4) {
Packit aea12f
		tmp = decode(tmpres, (uint8_t *) & data[i]);
Packit aea12f
		if (tmp < 0) {
Packit aea12f
			gnutls_free((*result));
Packit aea12f
			return tmp;
Packit aea12f
		}
Packit aea12f
		memcpy(&(*result)[j], tmpres, tmp);
Packit aea12f
		if (tmp < 3)
Packit aea12f
			ret -= (3 - tmp);
Packit aea12f
		j += 3;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return ret;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_srp_base64_encode:
Packit aea12f
 * @data: contain the raw data
Packit aea12f
 * @result: the place where base64 data will be copied
Packit aea12f
 * @result_size: holds the size of the result
Packit aea12f
 *
Packit aea12f
 * This function will convert the given data to printable data, using
Packit aea12f
 * the base64 encoding, as used in the libsrp.  This is the encoding
Packit aea12f
 * used in SRP password files.  If the provided buffer is not long
Packit aea12f
 * enough GNUTLS_E_SHORT_MEMORY_BUFFER is returned.
Packit aea12f
 *
Packit aea12f
 * Warning!  This base64 encoding is not the "standard" encoding, so
Packit aea12f
 * do not use it for non-SRP purposes.
Packit aea12f
 *
Packit aea12f
 * Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
Packit aea12f
 * long enough, or 0 on success.
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_srp_base64_encode(const gnutls_datum_t * data, char *result,
Packit aea12f
			 size_t * result_size)
Packit aea12f
{
Packit aea12f
	char *res;
Packit aea12f
	int size;
Packit aea12f
Packit aea12f
	size = _gnutls_sbase64_encode(data->data, data->size, &res;;
Packit aea12f
	if (size < 0)
Packit aea12f
		return size;
Packit aea12f
Packit aea12f
	if (result == NULL || *result_size < (size_t) size) {
Packit aea12f
		gnutls_free(res);
Packit aea12f
		*result_size = size;
Packit aea12f
		return GNUTLS_E_SHORT_MEMORY_BUFFER;
Packit aea12f
	} else {
Packit aea12f
		memcpy(result, res, size);
Packit aea12f
		gnutls_free(res);
Packit aea12f
		*result_size = size;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_srp_base64_encode2:
Packit aea12f
 * @data: contains the raw data
Packit aea12f
 * @result: will hold the newly allocated encoded data
Packit aea12f
 *
Packit aea12f
 * This function will convert the given data to printable data, using
Packit aea12f
 * the base64 encoding.  This is the encoding used in SRP password
Packit aea12f
 * files.  This function will allocate the required memory to hold
Packit aea12f
 * the encoded data.
Packit aea12f
 *
Packit aea12f
 * You should use gnutls_free() to free the returned data.
Packit aea12f
 *
Packit aea12f
 * Warning!  This base64 encoding is not the "standard" encoding, so
Packit aea12f
 * do not use it for non-SRP purposes.
Packit aea12f
 *
Packit aea12f
 * Returns: 0 on success, or an error code.
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_srp_base64_encode2(const gnutls_datum_t * data,
Packit aea12f
			       gnutls_datum_t * result)
Packit aea12f
{
Packit aea12f
	char *res;
Packit aea12f
	int size;
Packit aea12f
Packit aea12f
	size = _gnutls_sbase64_encode(data->data, data->size, &res;;
Packit aea12f
	if (size < 0)
Packit aea12f
		return size;
Packit aea12f
Packit aea12f
	if (result == NULL) {
Packit aea12f
		gnutls_free(res);
Packit aea12f
		return GNUTLS_E_INVALID_REQUEST;
Packit aea12f
	} else {
Packit aea12f
		result->data = (uint8_t *) res;
Packit aea12f
		result->size = size;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_srp_base64_decode:
Packit aea12f
 * @b64_data: contain the encoded data
Packit aea12f
 * @result: the place where decoded data will be copied
Packit aea12f
 * @result_size: holds the size of the result
Packit aea12f
 *
Packit aea12f
 * This function will decode the given encoded data, using the base64
Packit aea12f
 * encoding found in libsrp.
Packit aea12f
 *
Packit aea12f
 * Note that @b64_data should be null terminated.
Packit aea12f
 *
Packit aea12f
 * Warning!  This base64 encoding is not the "standard" encoding, so
Packit aea12f
 * do not use it for non-SRP purposes.
Packit aea12f
 *
Packit aea12f
 * Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
Packit aea12f
 * long enough, or 0 on success.
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_srp_base64_decode(const gnutls_datum_t * b64_data, char *result,
Packit aea12f
			 size_t * result_size)
Packit aea12f
{
Packit aea12f
	uint8_t *res;
Packit aea12f
	int size;
Packit aea12f
Packit aea12f
	size =
Packit aea12f
	    _gnutls_sbase64_decode((char *) b64_data->data, b64_data->size,
Packit aea12f
				   &res;;
Packit aea12f
	if (size < 0)
Packit aea12f
		return size;
Packit aea12f
Packit aea12f
	if (result == NULL || *result_size < (size_t) size) {
Packit aea12f
		gnutls_free(res);
Packit aea12f
		*result_size = size;
Packit aea12f
		return GNUTLS_E_SHORT_MEMORY_BUFFER;
Packit aea12f
	} else {
Packit aea12f
		memcpy(result, res, size);
Packit aea12f
		gnutls_free(res);
Packit aea12f
		*result_size = size;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_srp_base64_decode2:
Packit aea12f
 * @b64_data: contains the encoded data
Packit aea12f
 * @result: the place where decoded data lie
Packit aea12f
 *
Packit aea12f
 * This function will decode the given encoded data. The decoded data
Packit aea12f
 * will be allocated, and stored into result.  It will decode using
Packit aea12f
 * the base64 algorithm as used in libsrp.
Packit aea12f
 *
Packit aea12f
 * You should use gnutls_free() to free the returned data.
Packit aea12f
 *
Packit aea12f
 * Warning!  This base64 encoding is not the "standard" encoding, so
Packit aea12f
 * do not use it for non-SRP purposes.
Packit aea12f
 *
Packit aea12f
 * Returns: 0 on success, or an error code.
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_srp_base64_decode2(const gnutls_datum_t * b64_data,
Packit aea12f
			       gnutls_datum_t * result)
Packit aea12f
{
Packit aea12f
	uint8_t *ret;
Packit aea12f
	int size;
Packit aea12f
Packit aea12f
	size =
Packit aea12f
	    _gnutls_sbase64_decode((char *) b64_data->data, b64_data->size,
Packit aea12f
				   &ret;;
Packit aea12f
	if (size < 0)
Packit aea12f
		return size;
Packit aea12f
Packit aea12f
	if (result == NULL) {
Packit aea12f
		gnutls_free(ret);
Packit aea12f
		return GNUTLS_E_INVALID_REQUEST;
Packit aea12f
	} else {
Packit aea12f
		result->data = ret;
Packit aea12f
		result->size = size;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
#endif				/* ENABLE_SRP */