📄 asn1.c
字号:
/* Unix SMB/CIFS implementation. simple ASN1 routines Copyright (C) Andrew Tridgell 2001 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "lib/util/asn1.h"/* allocate an asn1 structure */struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx){ struct asn1_data *ret = talloc_zero(mem_ctx, struct asn1_data); if (ret == NULL) { DEBUG(0,("asn1_init failed! out of memory\n")); } return ret;}/* free an asn1 structure */void asn1_free(struct asn1_data *data){ talloc_free(data);}/* write to the ASN1 buffer, advancing the buffer pointer */bool asn1_write(struct asn1_data *data, const void *p, int len){ if (data->has_error) return false; if (data->length < data->ofs+len) { uint8_t *newp; newp = talloc_realloc(data, data->data, uint8_t, data->ofs+len); if (!newp) { asn1_free(data); data->has_error = true; return false; } data->data = newp; data->length = data->ofs+len; } memcpy(data->data + data->ofs, p, len); data->ofs += len; return true;}/* useful fn for writing a uint8_t */bool asn1_write_uint8(struct asn1_data *data, uint8_t v){ return asn1_write(data, &v, 1);}/* push a tag onto the asn1 data buffer. Used for nested structures */bool asn1_push_tag(struct asn1_data *data, uint8_t tag){ struct nesting *nesting; asn1_write_uint8(data, tag); nesting = talloc(data, struct nesting); if (!nesting) { data->has_error = true; return false; } nesting->start = data->ofs; nesting->next = data->nesting; data->nesting = nesting; return asn1_write_uint8(data, 0xff);}/* pop a tag */bool asn1_pop_tag(struct asn1_data *data){ struct nesting *nesting; size_t len; nesting = data->nesting; if (!nesting) { data->has_error = true; return false; } len = data->ofs - (nesting->start+1); /* yes, this is ugly. We don't know in advance how many bytes the length of a tag will take, so we assumed 1 byte. If we were wrong then we need to correct our mistake */ if (len > 0xFFFFFF) { data->data[nesting->start] = 0x84; if (!asn1_write_uint8(data, 0)) return false; if (!asn1_write_uint8(data, 0)) return false; if (!asn1_write_uint8(data, 0)) return false; if (!asn1_write_uint8(data, 0)) return false; memmove(data->data+nesting->start+5, data->data+nesting->start+1, len); data->data[nesting->start+1] = (len>>24) & 0xFF; data->data[nesting->start+2] = (len>>16) & 0xFF; data->data[nesting->start+3] = (len>>8) & 0xFF; data->data[nesting->start+4] = len&0xff; } else if (len > 0xFFFF) { data->data[nesting->start] = 0x83; if (!asn1_write_uint8(data, 0)) return false; if (!asn1_write_uint8(data, 0)) return false; if (!asn1_write_uint8(data, 0)) return false; memmove(data->data+nesting->start+4, data->data+nesting->start+1, len); data->data[nesting->start+1] = (len>>16) & 0xFF; data->data[nesting->start+2] = (len>>8) & 0xFF; data->data[nesting->start+3] = len&0xff; } else if (len > 255) { data->data[nesting->start] = 0x82; if (!asn1_write_uint8(data, 0)) return false; if (!asn1_write_uint8(data, 0)) return false; memmove(data->data+nesting->start+3, data->data+nesting->start+1, len); data->data[nesting->start+1] = len>>8; data->data[nesting->start+2] = len&0xff; } else if (len > 127) { data->data[nesting->start] = 0x81; if (!asn1_write_uint8(data, 0)) return false; memmove(data->data+nesting->start+2, data->data+nesting->start+1, len); data->data[nesting->start+1] = len; } else { data->data[nesting->start] = len; } data->nesting = nesting->next; talloc_free(nesting); return true;}/* "i" is the one's complement representation, as is the normal result of an * implicit signed->unsigned conversion */static bool push_int_bigendian(struct asn1_data *data, unsigned int i, bool negative){ uint8_t lowest = i & 0xFF; i = i >> 8; if (i != 0) if (!push_int_bigendian(data, i, negative)) return false; if (data->nesting->start+1 == data->ofs) { /* We did not write anything yet, looking at the highest * valued byte */ if (negative) { /* Don't write leading 0xff's */ if (lowest == 0xFF) return true; if ((lowest & 0x80) == 0) { /* The only exception for a leading 0xff is if * the highest bit is 0, which would indicate * a positive value */ if (!asn1_write_uint8(data, 0xff)) return false; } } else { if (lowest & 0x80) { /* The highest bit of a positive integer is 1, * this would indicate a negative number. Push * a 0 to indicate a positive one */ if (!asn1_write_uint8(data, 0)) return false; } } } return asn1_write_uint8(data, lowest);}/* write an Integer without the tag framing. Needed for example for the LDAP * Abandon Operation */bool asn1_write_implicit_Integer(struct asn1_data *data, int i){ if (i == -1) { /* -1 is special as it consists of all-0xff bytes. In push_int_bigendian this is the only case that is not properly handled, as all 0xff bytes would be handled as leading ones to be ignored. */ return asn1_write_uint8(data, 0xff); } else { return push_int_bigendian(data, i, i<0); }}/* write an integer */bool asn1_write_Integer(struct asn1_data *data, int i){ if (!asn1_push_tag(data, ASN1_INTEGER)) return false; if (!asn1_write_implicit_Integer(data, i)) return false; return asn1_pop_tag(data);}bool ber_write_OID_String(DATA_BLOB *blob, const char *OID){ uint_t v, v2; const char *p = (const char *)OID; char *newp; int i; v = strtoul(p, &newp, 10); if (newp[0] != '.') return false; p = newp + 1; v2 = strtoul(p, &newp, 10); if (newp[0] != '.') return false; p = newp + 1; /*the ber representation can't use more space then the string one */ *blob = data_blob(NULL, strlen(OID)); if (!blob->data) return false; blob->data[0] = 40*v + v2; i = 1; while (*p) { v = strtoul(p, &newp, 10); if (newp[0] == '.') { p = newp + 1; } else if (newp[0] == '\0') { p = newp; } else { data_blob_free(blob); return false; } if (v >= (1<<28)) blob->data[i++] = (0x80 | ((v>>28)&0x7f)); if (v >= (1<<21)) blob->data[i++] = (0x80 | ((v>>21)&0x7f)); if (v >= (1<<14)) blob->data[i++] = (0x80 | ((v>>14)&0x7f)); if (v >= (1<<7)) blob->data[i++] = (0x80 | ((v>>7)&0x7f)); blob->data[i++] = (v&0x7f); } blob->length = i; return true;}/* write an object ID to a ASN1 buffer */bool asn1_write_OID(struct asn1_data *data, const char *OID){ DATA_BLOB blob; if (!asn1_push_tag(data, ASN1_OID)) return false; if (!ber_write_OID_String(&blob, OID)) { data->has_error = true; return false; } if (!asn1_write(data, blob.data, blob.length)) { data->has_error = true; return false; } data_blob_free(&blob); return asn1_pop_tag(data);}/* write an octet string */bool asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length){ asn1_push_tag(data, ASN1_OCTET_STRING); asn1_write(data, p, length); asn1_pop_tag(data); return !data->has_error;}/* write a LDAP string */bool asn1_write_LDAPString(struct asn1_data *data, const char *s){ asn1_write(data, s, strlen(s)); return !data->has_error;}/* write a LDAP string from a DATA_BLOB */bool asn1_write_DATA_BLOB_LDAPString(struct asn1_data *data, const DATA_BLOB *s){ asn1_write(data, s->data, s->length); return !data->has_error;}/* write a general string */bool asn1_write_GeneralString(struct asn1_data *data, const char *s){ asn1_push_tag(data, ASN1_GENERAL_STRING); asn1_write_LDAPString(data, s); asn1_pop_tag(data); return !data->has_error;}bool asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob){ asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(num)); asn1_write(data, blob->data, blob->length); asn1_pop_tag(data); return !data->has_error;}/* write a BOOLEAN */bool asn1_write_BOOLEAN(struct asn1_data *data, bool v){ asn1_push_tag(data, ASN1_BOOLEAN); asn1_write_uint8(data, v ? 0xFF : 0); asn1_pop_tag(data); return !data->has_error;}bool asn1_read_BOOLEAN(struct asn1_data *data, bool *v){ uint8_t tmp = 0; asn1_start_tag(data, ASN1_BOOLEAN); asn1_read_uint8(data, &tmp); if (tmp == 0xFF) { *v = true; } else { *v = false; } asn1_end_tag(data); return !data->has_error;}/* check a BOOLEAN */bool asn1_check_BOOLEAN(struct asn1_data *data, bool v){ uint8_t b = 0; asn1_read_uint8(data, &b); if (b != ASN1_BOOLEAN) { data->has_error = true; return false; } asn1_read_uint8(data, &b); if (b != v) { data->has_error = true; return false; } return !data->has_error;}/* load a struct asn1_data structure with a lump of data, ready to be parsed */bool asn1_load(struct asn1_data *data, DATA_BLOB blob){ ZERO_STRUCTP(data); data->data = talloc_memdup(data, blob.data, blob.length); if (!data->data) { data->has_error = true; return false; } data->length = blob.length; return true;}/* Peek into an ASN1 buffer, not advancing the pointer */bool asn1_peek(struct asn1_data *data, void *p, int len){ if (data->has_error) return false; if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len) return false; if (data->ofs + len > data->length) { /* we need to mark the buffer as consumed, so the caller knows this was an out of data error, and not a decode error */ data->ofs = data->length; return false; } memcpy(p, data->data + data->ofs, len); return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -