Blame libfreerdp/crypto/per.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * ASN.1 Packed Encoding Rules (BER)
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/crypto/per.h>
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read PER length.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param length length
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL per_read_length(wStream* s, UINT16* length)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE byte;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 1)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT8(s, byte);
Packit 1fb8d4
Packit 1fb8d4
	if (byte & 0x80)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (Stream_GetRemainingLength(s) < 1)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		byte &= ~(0x80);
Packit 1fb8d4
		*length = (byte << 8);
Packit 1fb8d4
		Stream_Read_UINT8(s, byte);
Packit 1fb8d4
		*length += byte;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		*length = byte;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER length.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param length length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_length(wStream* s, int length)
Packit 1fb8d4
{
Packit 1fb8d4
	if (length > 0x7F)
Packit 1fb8d4
		Stream_Write_UINT16_BE(s, (length | 0x8000));
Packit 1fb8d4
	else
Packit 1fb8d4
		Stream_Write_UINT8(s, length);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read PER choice.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param choice choice
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL per_read_choice(wStream* s, BYTE* choice)
Packit 1fb8d4
{
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 1)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT8(s, *choice);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER CHOICE.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param choice index of chosen field
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_choice(wStream* s, BYTE choice)
Packit 1fb8d4
{
Packit 1fb8d4
	Stream_Write_UINT8(s, choice);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read PER selection.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param selection selection
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL per_read_selection(wStream* s, BYTE* selection)
Packit 1fb8d4
{
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 1)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT8(s, *selection);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER selection for OPTIONAL fields.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param selection bit map of selected fields
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_selection(wStream* s, BYTE selection)
Packit 1fb8d4
{
Packit 1fb8d4
	Stream_Write_UINT8(s, selection);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read PER number of sets.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param number number of sets
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL per_read_number_of_sets(wStream* s, BYTE* number)
Packit 1fb8d4
{
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 1)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT8(s, *number);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER number of sets for SET OF.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param number number of sets
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_number_of_sets(wStream* s, BYTE number)
Packit 1fb8d4
{
Packit 1fb8d4
	Stream_Write_UINT8(s, number);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read PER padding with zeros.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL per_read_padding(wStream* s, int length)
Packit 1fb8d4
{
Packit 1fb8d4
	if (((int) Stream_GetRemainingLength(s)) < length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Seek(s, length);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER padding with zeros.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_padding(wStream* s, int length)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < length; i++)
Packit 1fb8d4
		Stream_Write_UINT8(s, 0);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read PER INTEGER.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param integer integer
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL per_read_integer(wStream* s, UINT32* integer)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 length;
Packit 1fb8d4
Packit 1fb8d4
	if (!per_read_length(s, &length))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (length == 0)
Packit 1fb8d4
		*integer = 0;
Packit 1fb8d4
	else if (length == 1)
Packit 1fb8d4
		Stream_Read_UINT8(s, *integer);
Packit 1fb8d4
	else if (length == 2)
Packit 1fb8d4
		Stream_Read_UINT16_BE(s, *integer);
Packit 1fb8d4
	else
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER INTEGER.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param integer integer
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_integer(wStream* s, UINT32 integer)
Packit 1fb8d4
{
Packit 1fb8d4
	if (integer <= 0xFF)
Packit 1fb8d4
	{
Packit 1fb8d4
		per_write_length(s, 1);
Packit 1fb8d4
		Stream_Write_UINT8(s, integer);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (integer <= 0xFFFF)
Packit 1fb8d4
	{
Packit 1fb8d4
		per_write_length(s, 2);
Packit 1fb8d4
		Stream_Write_UINT16_BE(s, integer);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (integer <= 0xFFFFFFFF)
Packit 1fb8d4
	{
Packit 1fb8d4
		per_write_length(s, 4);
Packit 1fb8d4
		Stream_Write_UINT32_BE(s, integer);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read PER INTEGER (UINT16).
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param integer integer
Packit 1fb8d4
 * @param min minimum value
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL per_read_integer16(wStream* s, UINT16* integer, UINT16 min)
Packit 1fb8d4
{
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 2)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT16_BE(s, *integer);
Packit 1fb8d4
Packit 1fb8d4
	if (*integer + min > 0xFFFF)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	*integer += min;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER INTEGER (UINT16).
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param integer integer
Packit 1fb8d4
 * @param min minimum value
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_integer16(wStream* s, UINT16 integer, UINT16 min)
Packit 1fb8d4
{
Packit 1fb8d4
	Stream_Write_UINT16_BE(s, integer - min);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read PER ENUMERATED.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param enumerated enumerated
Packit 1fb8d4
 * @param count enumeration count
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL per_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
Packit 1fb8d4
{
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 1)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT8(s, *enumerated);
Packit 1fb8d4
Packit 1fb8d4
	/* check that enumerated value falls within expected range */
Packit 1fb8d4
	if (*enumerated + 1 > count)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER ENUMERATED.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param enumerated enumerated
Packit 1fb8d4
 * @param count enumeration count
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_enumerated(wStream* s, BYTE enumerated, BYTE count)
Packit 1fb8d4
{
Packit 1fb8d4
	Stream_Write_UINT8(s, enumerated);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read PER OBJECT_IDENTIFIER (OID).
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param oid object identifier (OID)
Packit 1fb8d4
 * @warning It works correctly only for limited set of OIDs.
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL per_read_object_identifier(wStream* s, BYTE oid[6])
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE t12;
Packit 1fb8d4
	UINT16 length;
Packit 1fb8d4
	BYTE a_oid[6];
Packit 1fb8d4
Packit 1fb8d4
	if (!per_read_length(s, &length))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (length != 5)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT8(s, t12); /* first two tuples */
Packit 1fb8d4
	a_oid[0] = t12 / 40;
Packit 1fb8d4
	a_oid[1] = t12 % 40;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT8(s, a_oid[2]); /* tuple 3 */
Packit 1fb8d4
	Stream_Read_UINT8(s, a_oid[3]); /* tuple 4 */
Packit 1fb8d4
	Stream_Read_UINT8(s, a_oid[4]); /* tuple 5 */
Packit 1fb8d4
	Stream_Read_UINT8(s, a_oid[5]); /* tuple 6 */
Packit 1fb8d4
Packit 1fb8d4
	if ((a_oid[0] == oid[0]) && (a_oid[1] == oid[1]) &&
Packit 1fb8d4
		(a_oid[2] == oid[2]) && (a_oid[3] == oid[3]) &&
Packit 1fb8d4
		(a_oid[4] == oid[4]) && (a_oid[5] == oid[5]))
Packit 1fb8d4
	{
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER OBJECT_IDENTIFIER (OID)
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param oid object identifier (oid)
Packit 1fb8d4
 * @warning It works correctly only for limited set of OIDs.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_object_identifier(wStream* s, BYTE oid[6])
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE t12 = oid[0] * 40 + oid[1];
Packit 1fb8d4
	Stream_Write_UINT8(s, 5); /* length */
Packit 1fb8d4
	Stream_Write_UINT8(s, t12); /* first two tuples */
Packit 1fb8d4
	Stream_Write_UINT8(s, oid[2]); /* tuple 3 */
Packit 1fb8d4
	Stream_Write_UINT8(s, oid[3]); /* tuple 4 */
Packit 1fb8d4
	Stream_Write_UINT8(s, oid[4]); /* tuple 5 */
Packit 1fb8d4
	Stream_Write_UINT8(s, oid[5]); /* tuple 6 */
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER string.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param str string
Packit 1fb8d4
 * @param length string length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_string(wStream* s, BYTE* str, int length)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < length; i++)
Packit 1fb8d4
		Stream_Write_UINT8(s, str[i]);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read PER OCTET_STRING.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param oct_str octet string
Packit 1fb8d4
 * @param length string length
Packit 1fb8d4
 * @param min minimum length
Packit 1fb8d4
 * @return
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL per_read_octet_string(wStream* s, BYTE* oct_str, int length, int min)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
	UINT16 mlength;
Packit 1fb8d4
	BYTE* a_oct_str;
Packit 1fb8d4
Packit 1fb8d4
	if (!per_read_length(s, &mlength))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (mlength + min != length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (((int) Stream_GetRemainingLength(s)) < length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	a_oct_str = Stream_Pointer(s);
Packit 1fb8d4
	Stream_Seek(s, length);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < length; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (a_oct_str[i] != oct_str[i])
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER OCTET_STRING
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param oct_str octet string
Packit 1fb8d4
 * @param length string length
Packit 1fb8d4
 * @param min minimum string length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_octet_string(wStream* s, BYTE* oct_str, int length, int min)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
	int mlength;
Packit 1fb8d4
Packit 1fb8d4
	mlength = (length - min >= 0) ? length - min : min;
Packit 1fb8d4
Packit 1fb8d4
	per_write_length(s, mlength);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < length; i++)
Packit 1fb8d4
		Stream_Write_UINT8(s, oct_str[i]);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read PER NumericString.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param num_str numeric string
Packit 1fb8d4
 * @param length string length
Packit 1fb8d4
 * @param min minimum string length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL per_read_numeric_string(wStream* s, int min)
Packit 1fb8d4
{
Packit 1fb8d4
	int length;
Packit 1fb8d4
	UINT16 mlength;
Packit 1fb8d4
Packit 1fb8d4
	if (!per_read_length(s, &mlength))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	length = (mlength + min + 1) / 2;
Packit 1fb8d4
Packit 1fb8d4
	if (((int) Stream_GetRemainingLength(s)) < length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Seek(s, length);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write PER NumericString.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param num_str numeric string
Packit 1fb8d4
 * @param length string length
Packit 1fb8d4
 * @param min minimum string length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void per_write_numeric_string(wStream* s, BYTE* num_str, int length, int min)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
	int mlength;
Packit 1fb8d4
	BYTE num, c1, c2;
Packit 1fb8d4
Packit 1fb8d4
	mlength = (length - min >= 0) ? length - min : min;
Packit 1fb8d4
Packit 1fb8d4
	per_write_length(s, mlength);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < length; i += 2)
Packit 1fb8d4
	{
Packit 1fb8d4
		c1 = num_str[i];
Packit 1fb8d4
		c2 = ((i + 1) < length) ? num_str[i + 1] : 0x30;
Packit 1fb8d4
Packit 1fb8d4
		c1 = (c1 - 0x30) % 10;
Packit 1fb8d4
		c2 = (c2 - 0x30) % 10;
Packit 1fb8d4
		num = (c1 << 4) | c2;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Write_UINT8(s, num); /* string */
Packit 1fb8d4
	}
Packit 1fb8d4
}