Blame asn1.c

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