2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2001
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "data_blob.h"
28 /* allocate an asn1 structure */
29 struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx)
31 struct asn1_data *ret = talloc_zero(mem_ctx, struct asn1_data);
35 /* free an asn1 structure */
36 void asn1_free(struct asn1_data *data)
41 /* write to the ASN1 buffer, advancing the buffer pointer */
42 bool asn1_write(struct asn1_data *data, const void *p, int len)
46 if (data->length < (size_t)data->ofs + len) {
48 newp = talloc_realloc(data, data->data, uint8_t, data->ofs+len);
50 data->has_error = true;
54 data->length = data->ofs+len;
56 memcpy(data->data + data->ofs, p, len);
61 /* useful fn for writing a uint8_t */
62 bool asn1_write_uint8(struct asn1_data *data, uint8_t v)
64 return asn1_write(data, &v, 1);
67 /* push a tag onto the asn1 data buffer. Used for nested structures */
68 bool asn1_push_tag(struct asn1_data *data, uint8_t tag)
70 struct nesting *nesting;
72 asn1_write_uint8(data, tag);
73 nesting = talloc(data, struct nesting);
75 data->has_error = true;
79 nesting->start = data->ofs;
80 nesting->next = data->nesting;
81 data->nesting = nesting;
82 return asn1_write_uint8(data, 0xff);
86 bool asn1_pop_tag(struct asn1_data *data)
88 struct nesting *nesting;
91 nesting = data->nesting;
94 data->has_error = true;
97 len = data->ofs - (nesting->start+1);
98 /* yes, this is ugly. We don't know in advance how many bytes the length
99 of a tag will take, so we assumed 1 byte. If we were wrong then we
100 need to correct our mistake */
101 if (len > 0xFFFFFF) {
102 data->data[nesting->start] = 0x84;
103 if (!asn1_write_uint8(data, 0)) return false;
104 if (!asn1_write_uint8(data, 0)) return false;
105 if (!asn1_write_uint8(data, 0)) return false;
106 if (!asn1_write_uint8(data, 0)) return false;
107 memmove(data->data+nesting->start+5, data->data+nesting->start+1, len);
108 data->data[nesting->start+1] = (len>>24) & 0xFF;
109 data->data[nesting->start+2] = (len>>16) & 0xFF;
110 data->data[nesting->start+3] = (len>>8) & 0xFF;
111 data->data[nesting->start+4] = len&0xff;
112 } else if (len > 0xFFFF) {
113 data->data[nesting->start] = 0x83;
114 if (!asn1_write_uint8(data, 0)) return false;
115 if (!asn1_write_uint8(data, 0)) return false;
116 if (!asn1_write_uint8(data, 0)) return false;
117 memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
118 data->data[nesting->start+1] = (len>>16) & 0xFF;
119 data->data[nesting->start+2] = (len>>8) & 0xFF;
120 data->data[nesting->start+3] = len&0xff;
121 } else if (len > 255) {
122 data->data[nesting->start] = 0x82;
123 if (!asn1_write_uint8(data, 0)) return false;
124 if (!asn1_write_uint8(data, 0)) return false;
125 memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
126 data->data[nesting->start+1] = len>>8;
127 data->data[nesting->start+2] = len&0xff;
128 } else if (len > 127) {
129 data->data[nesting->start] = 0x81;
130 if (!asn1_write_uint8(data, 0)) return false;
131 memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
132 data->data[nesting->start+1] = len;
134 data->data[nesting->start] = len;
137 data->nesting = nesting->next;
138 talloc_free(nesting);
142 bool ber_write_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *OID)
145 const char *p = (const char *)OID;
149 v = strtoul(p, &newp, 10);
150 if (newp[0] != '.') return false;
153 v2 = strtoul(p, &newp, 10);
154 if (newp[0] != '.') return false;
157 /*the ber representation can't use more space then the string one */
158 *blob = data_blob_talloc(mem_ctx, NULL, strlen(OID));
159 if (!blob->data) return false;
161 blob->data[0] = 40*v + v2;
165 v = strtoul(p, &newp, 10);
166 if (newp[0] == '.') {
168 } else if (newp[0] == '\0') {
171 data_blob_free(blob);
174 if (v >= (1<<28)) blob->data[i++] = (0x80 | ((v>>28)&0x7f));
175 if (v >= (1<<21)) blob->data[i++] = (0x80 | ((v>>21)&0x7f));
176 if (v >= (1<<14)) blob->data[i++] = (0x80 | ((v>>14)&0x7f));
177 if (v >= (1<<7)) blob->data[i++] = (0x80 | ((v>>7)&0x7f));
178 blob->data[i++] = (v&0x7f);
186 /* write an object ID to a ASN1 buffer */
187 bool asn1_write_OID(struct asn1_data *data, const char *OID)
191 if (!asn1_push_tag(data, ASN1_OID)) return false;
193 if (!ber_write_OID_String(NULL, &blob, OID)) {
194 data->has_error = true;
198 if (!asn1_write(data, blob.data, blob.length)) {
199 data_blob_free(&blob);
200 data->has_error = true;
203 data_blob_free(&blob);
204 return asn1_pop_tag(data);
207 /* write an octet string */
208 bool asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length)
210 asn1_push_tag(data, ASN1_OCTET_STRING);
211 asn1_write(data, p, length);
213 return !data->has_error;