Blame asn1.c

Packit 5f9837
/* 
Packit 5f9837
   Unix SMB/CIFS implementation.
Packit 5f9837
   simple ASN1 routines
Packit 5f9837
   Copyright (C) Andrew Tridgell 2001
Packit 5f9837
   
Packit 5f9837
   This program is free software; you can redistribute it and/or modify
Packit 5f9837
   it under the terms of the GNU General Public License as published by
Packit 5f9837
   the Free Software Foundation; either version 3 of the License, or
Packit 5f9837
   (at your option) any later version.
Packit 5f9837
   
Packit 5f9837
   This program is distributed in the hope that it will be useful,
Packit 5f9837
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5f9837
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 5f9837
   GNU General Public License for more details.
Packit 5f9837
   
Packit 5f9837
   You should have received a copy of the GNU General Public License
Packit 5f9837
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 5f9837
*/
Packit 5f9837
Packit 5f9837
#include <string.h>
Packit 5f9837
#include <talloc.h>
Packit 5f9837
#include <stdint.h>
Packit 5f9837
#include <stdbool.h>
Packit 5f9837
Packit 5f9837
#include "data_blob.h"
Packit 5f9837
#include "asn1.h"
Packit 5f9837
Packit 5f9837
/* allocate an asn1 structure */
Packit 5f9837
struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx)
Packit 5f9837
{
Packit 5f9837
	struct asn1_data *ret = talloc_zero(mem_ctx, struct asn1_data);
Packit 5f9837
	return ret;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* free an asn1 structure */
Packit 5f9837
void asn1_free(struct asn1_data *data)
Packit 5f9837
{
Packit 5f9837
	talloc_free(data);
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* write to the ASN1 buffer, advancing the buffer pointer */
Packit 5f9837
bool asn1_write(struct asn1_data *data, const void *p, int len)
Packit 5f9837
{
Packit 5f9837
	if (data->has_error)
Packit 5f9837
		return false;
Packit 5f9837
	if (data->length < (size_t)data->ofs + len) {
Packit 5f9837
		uint8_t *newp;
Packit 5f9837
		newp = talloc_realloc(data, data->data, uint8_t, data->ofs+len);
Packit 5f9837
		if (!newp) {
Packit 5f9837
			data->has_error = true;
Packit 5f9837
			return false;
Packit 5f9837
		}
Packit 5f9837
		data->data = newp;
Packit 5f9837
		data->length = data->ofs+len;
Packit 5f9837
	}
Packit 5f9837
	memcpy(data->data + data->ofs, p, len);
Packit 5f9837
	data->ofs += len;
Packit 5f9837
	return true;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* useful fn for writing a uint8_t */
Packit 5f9837
bool asn1_write_uint8(struct asn1_data *data, uint8_t v)
Packit 5f9837
{
Packit 5f9837
	return asn1_write(data, &v, 1);
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* push a tag onto the asn1 data buffer. Used for nested structures */
Packit 5f9837
bool asn1_push_tag(struct asn1_data *data, uint8_t tag)
Packit 5f9837
{
Packit 5f9837
	struct nesting *nesting;
Packit 5f9837
Packit 5f9837
	asn1_write_uint8(data, tag);
Packit 5f9837
	nesting = talloc(data, struct nesting);
Packit 5f9837
	if (!nesting) {
Packit 5f9837
		data->has_error = true;
Packit 5f9837
		return false;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	nesting->start = data->ofs;
Packit 5f9837
	nesting->next = data->nesting;
Packit 5f9837
	data->nesting = nesting;
Packit 5f9837
	return asn1_write_uint8(data, 0xff);
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* pop a tag */
Packit 5f9837
bool asn1_pop_tag(struct asn1_data *data)
Packit 5f9837
{
Packit 5f9837
	struct nesting *nesting;
Packit 5f9837
	size_t len;
Packit 5f9837
Packit 5f9837
	nesting = data->nesting;
Packit 5f9837
Packit 5f9837
	if (!nesting) {
Packit 5f9837
		data->has_error = true;
Packit 5f9837
		return false;
Packit 5f9837
	}
Packit 5f9837
	len = data->ofs - (nesting->start+1);
Packit 5f9837
	/* yes, this is ugly. We don't know in advance how many bytes the length
Packit 5f9837
	   of a tag will take, so we assumed 1 byte. If we were wrong then we 
Packit 5f9837
	   need to correct our mistake */
Packit 5f9837
	if (len > 0xFFFFFF) {
Packit 5f9837
		data->data[nesting->start] = 0x84;
Packit 5f9837
		if (!asn1_write_uint8(data, 0)) return false;
Packit 5f9837
		if (!asn1_write_uint8(data, 0)) return false;
Packit 5f9837
		if (!asn1_write_uint8(data, 0)) return false;
Packit 5f9837
		if (!asn1_write_uint8(data, 0)) return false;
Packit 5f9837
		memmove(data->data+nesting->start+5, data->data+nesting->start+1, len);
Packit 5f9837
		data->data[nesting->start+1] = (len>>24) & 0xFF;
Packit 5f9837
		data->data[nesting->start+2] = (len>>16) & 0xFF;
Packit 5f9837
		data->data[nesting->start+3] = (len>>8) & 0xFF;
Packit 5f9837
		data->data[nesting->start+4] = len&0xff;
Packit 5f9837
	} else if (len > 0xFFFF) {
Packit 5f9837
		data->data[nesting->start] = 0x83;
Packit 5f9837
		if (!asn1_write_uint8(data, 0)) return false;
Packit 5f9837
		if (!asn1_write_uint8(data, 0)) return false;
Packit 5f9837
		if (!asn1_write_uint8(data, 0)) return false;
Packit 5f9837
		memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
Packit 5f9837
		data->data[nesting->start+1] = (len>>16) & 0xFF;
Packit 5f9837
		data->data[nesting->start+2] = (len>>8) & 0xFF;
Packit 5f9837
		data->data[nesting->start+3] = len&0xff;
Packit 5f9837
	} else if (len > 255) {
Packit 5f9837
		data->data[nesting->start] = 0x82;
Packit 5f9837
		if (!asn1_write_uint8(data, 0)) return false;
Packit 5f9837
		if (!asn1_write_uint8(data, 0)) return false;
Packit 5f9837
		memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
Packit 5f9837
		data->data[nesting->start+1] = len>>8;
Packit 5f9837
		data->data[nesting->start+2] = len&0xff;
Packit 5f9837
	} else if (len > 127) {
Packit 5f9837
		data->data[nesting->start] = 0x81;
Packit 5f9837
		if (!asn1_write_uint8(data, 0)) return false;
Packit 5f9837
		memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
Packit 5f9837
		data->data[nesting->start+1] = len;
Packit 5f9837
	} else {
Packit 5f9837
		data->data[nesting->start] = len;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	data->nesting = nesting->next;
Packit 5f9837
	talloc_free(nesting);
Packit 5f9837
	return true;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
bool ber_write_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *OID)
Packit 5f9837
{
Packit 5f9837
	unsigned int v, v2;
Packit 5f9837
	const char *p = (const char *)OID;
Packit 5f9837
	char *newp;
Packit 5f9837
	int i;
Packit 5f9837
Packit 5f9837
	v = strtoul(p, &newp, 10);
Packit 5f9837
	if (newp[0] != '.') return false;
Packit 5f9837
	p = newp + 1;
Packit 5f9837
Packit 5f9837
	v2 = strtoul(p, &newp, 10);
Packit 5f9837
	if (newp[0] != '.') return false;
Packit 5f9837
	p = newp + 1;
Packit 5f9837
Packit 5f9837
	/*the ber representation can't use more space then the string one */
Packit 5f9837
	*blob = data_blob_talloc(mem_ctx, NULL, strlen(OID));
Packit 5f9837
	if (!blob->data) return false;
Packit 5f9837
Packit 5f9837
	blob->data[0] = 40*v + v2;
Packit 5f9837
Packit 5f9837
	i = 1;
Packit 5f9837
	while (*p) {
Packit 5f9837
		v = strtoul(p, &newp, 10);
Packit 5f9837
		if (newp[0] == '.') {
Packit 5f9837
			p = newp + 1;
Packit 5f9837
		} else if (newp[0] == '\0') {
Packit 5f9837
			p = newp;
Packit 5f9837
		} else {
Packit 5f9837
			data_blob_free(blob);
Packit 5f9837
			return false;
Packit 5f9837
		}
Packit 5f9837
		if (v >= (1<<28)) blob->data[i++] = (0x80 | ((v>>28)&0x7f));
Packit 5f9837
		if (v >= (1<<21)) blob->data[i++] = (0x80 | ((v>>21)&0x7f));
Packit 5f9837
		if (v >= (1<<14)) blob->data[i++] = (0x80 | ((v>>14)&0x7f));
Packit 5f9837
		if (v >= (1<<7)) blob->data[i++] = (0x80 | ((v>>7)&0x7f));
Packit 5f9837
		blob->data[i++] = (v&0x7f);
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	blob->length = i;
Packit 5f9837
Packit 5f9837
	return true;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* write an object ID to a ASN1 buffer */
Packit 5f9837
bool asn1_write_OID(struct asn1_data *data, const char *OID)
Packit 5f9837
{
Packit 5f9837
	DATA_BLOB blob;
Packit 5f9837
Packit 5f9837
	if (!asn1_push_tag(data, ASN1_OID)) return false;
Packit 5f9837
Packit 5f9837
	if (!ber_write_OID_String(NULL, &blob, OID)) {
Packit 5f9837
		data->has_error = true;
Packit 5f9837
		return false;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (!asn1_write(data, blob.data, blob.length)) {
Packit 5f9837
		data_blob_free(&blob;;
Packit 5f9837
		data->has_error = true;
Packit 5f9837
		return false;
Packit 5f9837
	}
Packit 5f9837
	data_blob_free(&blob;;
Packit 5f9837
	return asn1_pop_tag(data);
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* write an octet string */
Packit 5f9837
bool asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length)
Packit 5f9837
{
Packit 5f9837
	asn1_push_tag(data, ASN1_OCTET_STRING);
Packit 5f9837
	asn1_write(data, p, length);
Packit 5f9837
	asn1_pop_tag(data);
Packit 5f9837
	return !data->has_error;
Packit 5f9837
}
Packit 5f9837