krypt-core 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/ext/krypt/core/Makefile +221 -0
- data/ext/krypt/core/binyo-error.h +40 -0
- data/ext/krypt/core/binyo-io-buffer.h +54 -0
- data/ext/krypt/core/binyo-io.h +131 -0
- data/ext/krypt/core/extconf.h +8 -0
- data/ext/krypt/core/extconf.rb +80 -0
- data/ext/krypt/core/krypt-core.c +110 -0
- data/ext/krypt/core/krypt-core.h +97 -0
- data/ext/krypt/core/krypt-core.o +0 -0
- data/ext/krypt/core/krypt-provider.h +86 -0
- data/ext/krypt/core/krypt_asn1-internal.c +681 -0
- data/ext/krypt/core/krypt_asn1-internal.h +117 -0
- data/ext/krypt/core/krypt_asn1-internal.o +0 -0
- data/ext/krypt/core/krypt_asn1.c +2109 -0
- data/ext/krypt/core/krypt_asn1.h +88 -0
- data/ext/krypt/core/krypt_asn1.o +0 -0
- data/ext/krypt/core/krypt_asn1_codec.c +973 -0
- data/ext/krypt/core/krypt_asn1_codec.o +0 -0
- data/ext/krypt/core/krypt_asn1_in_adapter.c +178 -0
- data/ext/krypt/core/krypt_asn1_in_adapter.o +0 -0
- data/ext/krypt/core/krypt_asn1_in_chunked.c +292 -0
- data/ext/krypt/core/krypt_asn1_in_chunked.o +0 -0
- data/ext/krypt/core/krypt_asn1_in_definite.c +156 -0
- data/ext/krypt/core/krypt_asn1_in_definite.o +0 -0
- data/ext/krypt/core/krypt_asn1_parser.c +592 -0
- data/ext/krypt/core/krypt_asn1_parser.o +0 -0
- data/ext/krypt/core/krypt_asn1_template-internal.h +185 -0
- data/ext/krypt/core/krypt_asn1_template.c +459 -0
- data/ext/krypt/core/krypt_asn1_template.h +56 -0
- data/ext/krypt/core/krypt_asn1_template.o +0 -0
- data/ext/krypt/core/krypt_asn1_template_encoder.c +76 -0
- data/ext/krypt/core/krypt_asn1_template_encoder.o +0 -0
- data/ext/krypt/core/krypt_asn1_template_parser.c +1176 -0
- data/ext/krypt/core/krypt_asn1_template_parser.o +0 -0
- data/ext/krypt/core/krypt_b64-internal.h +38 -0
- data/ext/krypt/core/krypt_b64.c +391 -0
- data/ext/krypt/core/krypt_b64.h +41 -0
- data/ext/krypt/core/krypt_b64.o +0 -0
- data/ext/krypt/core/krypt_digest.c +391 -0
- data/ext/krypt/core/krypt_digest.h +51 -0
- data/ext/krypt/core/krypt_digest.o +0 -0
- data/ext/krypt/core/krypt_error.c +221 -0
- data/ext/krypt/core/krypt_error.h +46 -0
- data/ext/krypt/core/krypt_error.o +0 -0
- data/ext/krypt/core/krypt_hex-internal.h +36 -0
- data/ext/krypt/core/krypt_hex.c +255 -0
- data/ext/krypt/core/krypt_hex.h +41 -0
- data/ext/krypt/core/krypt_hex.o +0 -0
- data/ext/krypt/core/krypt_io.c +65 -0
- data/ext/krypt/core/krypt_io.h +56 -0
- data/ext/krypt/core/krypt_io.o +0 -0
- data/ext/krypt/core/krypt_io_in_pem.c +397 -0
- data/ext/krypt/core/krypt_io_in_pem.o +0 -0
- data/ext/krypt/core/krypt_missing.c +238 -0
- data/ext/krypt/core/krypt_missing.h +62 -0
- data/ext/krypt/core/krypt_missing.o +0 -0
- data/ext/krypt/core/krypt_pem.c +171 -0
- data/ext/krypt/core/krypt_pem.o +0 -0
- data/ext/krypt/core/krypt_provider-internal.h +40 -0
- data/ext/krypt/core/krypt_provider.c +136 -0
- data/ext/krypt/core/krypt_provider.o +0 -0
- data/ext/krypt/core/kryptcore.so +0 -0
- data/ext/krypt/core/mkmf.log +130 -0
- data/lib/krypt-core/version.rb +3 -0
- data/lib/krypt-core.rb +35 -0
- data/lib/kryptcore.so +0 -0
- data/spec/README +2 -0
- data/test/README +2 -0
- data/test/res/certificate.cer +0 -0
- data/test/resources.rb +48 -0
- data/test/scratch.rb +17 -0
- metadata +150 -0
@@ -0,0 +1,681 @@
|
|
1
|
+
/*
|
2
|
+
* krypt-core API - C implementation
|
3
|
+
*
|
4
|
+
* Copyright (c) 2011-2013
|
5
|
+
* Hiroshi Nakamura <nahi@ruby-lang.org>
|
6
|
+
* Martin Bosslet <martin.bosslet@gmail.com>
|
7
|
+
* All rights reserved.
|
8
|
+
*
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining
|
10
|
+
* a copy of this software and associated documentation files (the
|
11
|
+
* "Software"), to deal in the Software without restriction, including
|
12
|
+
* without limitation the rights to use, copy, modify, merge, publish,
|
13
|
+
* distribute, sublicense, and/or sell copies of the Software, and to
|
14
|
+
* permit persons to whom the Software is furnished to do so, subject to
|
15
|
+
* the following conditions:
|
16
|
+
*
|
17
|
+
* The above copyright notice and this permission notice shall be
|
18
|
+
* included in all copies or substantial portions of the Software.
|
19
|
+
*
|
20
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
21
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
22
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
23
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
24
|
+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
25
|
+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
26
|
+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27
|
+
*/
|
28
|
+
|
29
|
+
#include <limits.h>
|
30
|
+
#include "krypt-core.h"
|
31
|
+
#include "krypt_asn1-internal.h"
|
32
|
+
|
33
|
+
static const int KRYPT_ASN1_TAG_LIMIT = INT_MAX >> CHAR_BIT_MINUS_ONE;
|
34
|
+
static const size_t KRYPT_ASN1_LENGTH_LIMIT = SIZE_MAX >> CHAR_BIT;
|
35
|
+
|
36
|
+
#define int_next_byte(in, b) \
|
37
|
+
do { \
|
38
|
+
if (binyo_instream_read((in), &(b), 1) != BINYO_OK) { \
|
39
|
+
krypt_error_add("Could not read byte from stream"); \
|
40
|
+
return KRYPT_ERR; \
|
41
|
+
} \
|
42
|
+
} while (0) \
|
43
|
+
|
44
|
+
static int int_parse_tag(uint8_t b, binyo_instream *in, krypt_asn1_header *out);
|
45
|
+
static int int_parse_complex_tag(uint8_t b, binyo_instream *in, krypt_asn1_header *out);
|
46
|
+
static void int_parse_primitive_tag(uint8_t b, krypt_asn1_header *out);
|
47
|
+
static int int_parse_length(binyo_instream *in, krypt_asn1_header *out);
|
48
|
+
static int int_parse_complex_definite_length(uint8_t b, binyo_instream *in, krypt_asn1_header *out);
|
49
|
+
static int int_parse_read_exactly(binyo_instream *in, size_t n, uint8_t **out, size_t *outlen);
|
50
|
+
static int int_consume_stream(binyo_instream *in, uint8_t **out, size_t *outlen);
|
51
|
+
static void int_compute_tag(krypt_asn1_header *header);
|
52
|
+
static void int_compute_length(krypt_asn1_header *header);
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Parses a krypt_asn1_header from the krypt_instream at its current
|
56
|
+
* position.
|
57
|
+
*
|
58
|
+
* @param in The binyo_instream to be parsed from
|
59
|
+
* @param out On successful parsing, an instance of krypt_asn1_header
|
60
|
+
* will be assigned
|
61
|
+
* @return KRYPT_OK if a new header was successfully parsed, KRYPT_ASN1_EOF if EOF
|
62
|
+
* has been reached, KRYPT_ERR in case of errors
|
63
|
+
*/
|
64
|
+
int
|
65
|
+
krypt_asn1_next_header(binyo_instream *in, krypt_asn1_header **out)
|
66
|
+
{
|
67
|
+
ssize_t read;
|
68
|
+
uint8_t b;
|
69
|
+
krypt_asn1_header *header;
|
70
|
+
|
71
|
+
if (!in) return KRYPT_ERR;
|
72
|
+
|
73
|
+
read = binyo_instream_read(in, &b, 1);
|
74
|
+
if (read == BINYO_IO_EOF) return KRYPT_ASN1_EOF;
|
75
|
+
if (read == BINYO_ERR) {
|
76
|
+
krypt_error_add("Error when parsing stream");
|
77
|
+
return KRYPT_ERR;
|
78
|
+
}
|
79
|
+
|
80
|
+
header = krypt_asn1_header_new();
|
81
|
+
|
82
|
+
if (int_parse_tag(b, in, header) == KRYPT_ERR) {
|
83
|
+
krypt_error_add("Error when parsing tag");
|
84
|
+
goto error;
|
85
|
+
}
|
86
|
+
if (int_parse_length(in, header) == KRYPT_ERR) {
|
87
|
+
krypt_error_add("Error when parsing length");
|
88
|
+
goto error;
|
89
|
+
}
|
90
|
+
if (header->is_infinite && !header->is_constructed) {
|
91
|
+
krypt_error_add("Infinite length values must be constructed");
|
92
|
+
goto error;
|
93
|
+
}
|
94
|
+
|
95
|
+
*out = header;
|
96
|
+
return KRYPT_OK;
|
97
|
+
error:
|
98
|
+
krypt_asn1_header_free(header);
|
99
|
+
return KRYPT_ERR;
|
100
|
+
}
|
101
|
+
|
102
|
+
/**
|
103
|
+
* Based on the last header that was parsed, this function skips the bytes
|
104
|
+
* that represent the value of the object represented by the header.
|
105
|
+
*
|
106
|
+
* @param in The binyo_instream that the header was parsed from
|
107
|
+
* @param last The last header that was parsed from the stream
|
108
|
+
* @return KRYPT_OK if successful, KRYPT_ERR otherwise
|
109
|
+
*/
|
110
|
+
int
|
111
|
+
krypt_asn1_skip_value(binyo_instream *in, krypt_asn1_header *last)
|
112
|
+
{
|
113
|
+
if (!in) return KRYPT_ERR;
|
114
|
+
if (!last) return KRYPT_ERR;
|
115
|
+
if (binyo_instream_skip(in, last->length) == BINYO_OK)
|
116
|
+
return KRYPT_OK;
|
117
|
+
else
|
118
|
+
return KRYPT_ERR;
|
119
|
+
}
|
120
|
+
|
121
|
+
/**
|
122
|
+
* Based on the last header that was parsed, this function reads and returns
|
123
|
+
* the bytes that represent the value of the object represented by the header.
|
124
|
+
*
|
125
|
+
* @param in The binyo_instream that the header was parsed from
|
126
|
+
* @param last The last header that was parsed from the stream
|
127
|
+
* @param out A pointer to the uint8_t* that shall receive the value
|
128
|
+
* representing the currently parsed object
|
129
|
+
* @param outlen The length of the value that has been parsed
|
130
|
+
* @return KRYPT_OK if successful, or KRYPT_ERR otherwise
|
131
|
+
*/
|
132
|
+
int
|
133
|
+
krypt_asn1_get_value(binyo_instream *in, krypt_asn1_header *last, uint8_t **out, size_t *outlen)
|
134
|
+
{
|
135
|
+
if (!in) return KRYPT_ERR;
|
136
|
+
if (!last) return KRYPT_ERR;
|
137
|
+
|
138
|
+
if (!last->is_infinite) {
|
139
|
+
if (int_parse_read_exactly(in, last->length, out, outlen) == KRYPT_ERR)
|
140
|
+
return KRYPT_ERR;
|
141
|
+
*outlen = last->length;
|
142
|
+
return KRYPT_OK;
|
143
|
+
}
|
144
|
+
else {
|
145
|
+
int ret;
|
146
|
+
binyo_instream *inf_stream = krypt_instream_new_chunked(in, 0);
|
147
|
+
ret = int_consume_stream(inf_stream, out, outlen);
|
148
|
+
binyo_instream_free(inf_stream);
|
149
|
+
return ret;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
/**
|
154
|
+
* Based on the last header that was parsed, this function returns a
|
155
|
+
* krypt_instream that allows to read the bytes that represent the value of
|
156
|
+
* the object represented by the header in streaming manner.
|
157
|
+
*
|
158
|
+
* @param in The binyo_instream that the header was parsed from
|
159
|
+
* @param last The last header that was parsed from the stream
|
160
|
+
* @param values_only Only used for infinite length values. If 0, all subsequent
|
161
|
+
* value bytes including headers will be read from the returned
|
162
|
+
* stream. If 1 (or generally non-0), only the raw values
|
163
|
+
* excluding the headers will be read from the value stream.
|
164
|
+
* This comes in handy e.g. when reading the chunked value of an
|
165
|
+
* infinite-length octet string. For definite length values, the
|
166
|
+
* returned stream will always read values including the
|
167
|
+
* headers.
|
168
|
+
* @return A binyo_instream * allowing to read the bytes representing
|
169
|
+
* the value of the currently parsed object or NULL if an error
|
170
|
+
* occurred.
|
171
|
+
*/
|
172
|
+
binyo_instream *
|
173
|
+
krypt_asn1_get_value_stream(binyo_instream *in, krypt_asn1_header *last, int values_only)
|
174
|
+
{
|
175
|
+
if (!in) return NULL;
|
176
|
+
if (!last) return NULL;
|
177
|
+
|
178
|
+
if (last->is_infinite) {
|
179
|
+
return krypt_instream_new_chunked(in, values_only);
|
180
|
+
}
|
181
|
+
else {
|
182
|
+
return krypt_instream_new_definite(in, last->length);
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
/**
|
187
|
+
* Writes the encoding of a header to the supplied krypt_outstream.
|
188
|
+
*
|
189
|
+
* @param out The binyo_outstream where the header shall be encoded
|
190
|
+
* to
|
191
|
+
* @param header The header that shall be encoded
|
192
|
+
* @return KRYPT_OK if successful, KRYPT_ERR otherwise
|
193
|
+
*/
|
194
|
+
int
|
195
|
+
krypt_asn1_header_encode(binyo_outstream *out, krypt_asn1_header *header)
|
196
|
+
{
|
197
|
+
uint8_t *buf;
|
198
|
+
size_t hlen;
|
199
|
+
|
200
|
+
if (!out) return KRYPT_ERR;
|
201
|
+
if (!header) return KRYPT_ERR;
|
202
|
+
|
203
|
+
if (!header->tag_bytes)
|
204
|
+
int_compute_tag(header);
|
205
|
+
|
206
|
+
if (!header->length_bytes)
|
207
|
+
int_compute_length(header);
|
208
|
+
|
209
|
+
hlen = header->tag_len + header->length_len;
|
210
|
+
buf = ALLOCA_N(uint8_t, hlen);
|
211
|
+
memcpy(buf, header->tag_bytes, header->tag_len);
|
212
|
+
memcpy(buf + header->tag_len, header->length_bytes, header->length_len);
|
213
|
+
if (binyo_outstream_write(out, buf, hlen) == BINYO_ERR) return KRYPT_ERR;
|
214
|
+
return KRYPT_OK;
|
215
|
+
}
|
216
|
+
|
217
|
+
/**
|
218
|
+
* Writes the encoding of an krypt_asn1_object (header + value) to the
|
219
|
+
* supplied binyo_outstream.
|
220
|
+
*
|
221
|
+
* @param out The binyo_outstream where the object shall be encoded
|
222
|
+
* to
|
223
|
+
* @param object The object that shall be encoded
|
224
|
+
* @return KRYPT_OK if successful, KRYPT_ERR otherwise
|
225
|
+
*/
|
226
|
+
int
|
227
|
+
krypt_asn1_object_encode(binyo_outstream *out, krypt_asn1_object *object)
|
228
|
+
{
|
229
|
+
if (!object) return KRYPT_ERR;
|
230
|
+
if (krypt_asn1_header_encode(out, object->header) == KRYPT_ERR) return KRYPT_ERR;
|
231
|
+
if (!object->bytes) return KRYPT_OK;
|
232
|
+
if (object->bytes_len == 0) return KRYPT_OK;
|
233
|
+
if (binyo_outstream_write(out, object->bytes, object->bytes_len) == BINYO_ERR) return KRYPT_ERR;
|
234
|
+
return KRYPT_OK;
|
235
|
+
}
|
236
|
+
|
237
|
+
/**
|
238
|
+
* Creates a new krypt_asn1_header struct.
|
239
|
+
* @return a newly allocated krypt_asn1_header
|
240
|
+
*/
|
241
|
+
krypt_asn1_header *
|
242
|
+
krypt_asn1_header_new(void)
|
243
|
+
{
|
244
|
+
krypt_asn1_header *ret;
|
245
|
+
|
246
|
+
ret = ALLOC(krypt_asn1_header);
|
247
|
+
memset(ret, 0, sizeof(krypt_asn1_header));
|
248
|
+
return ret;
|
249
|
+
}
|
250
|
+
|
251
|
+
/**
|
252
|
+
* Frees a krypt_asn1_header and its members.
|
253
|
+
*
|
254
|
+
* @param header The header to be freed
|
255
|
+
*/
|
256
|
+
void
|
257
|
+
krypt_asn1_header_free(krypt_asn1_header *header)
|
258
|
+
{
|
259
|
+
if (!header) return;
|
260
|
+
if (header->tag_bytes)
|
261
|
+
xfree(header->tag_bytes);
|
262
|
+
if (header->length_bytes)
|
263
|
+
xfree(header->length_bytes);
|
264
|
+
xfree(header);
|
265
|
+
}
|
266
|
+
|
267
|
+
/**
|
268
|
+
* Allocates a new krypt_asn1_object given a header and the value encoding.
|
269
|
+
* It does *not* copy value, so the value pointer shall only be freed by a
|
270
|
+
* subsequent call to krypt_asn1_object_free.
|
271
|
+
*
|
272
|
+
* @param header The header corresponding to the value
|
273
|
+
* @param value The raw byte encoding of the value
|
274
|
+
* @param len The length of the byte encoding
|
275
|
+
*/
|
276
|
+
krypt_asn1_object *
|
277
|
+
krypt_asn1_object_new_value(krypt_asn1_header *header, uint8_t *value, size_t len)
|
278
|
+
{
|
279
|
+
krypt_asn1_object *obj;
|
280
|
+
|
281
|
+
obj = krypt_asn1_object_new(header);
|
282
|
+
obj->bytes = value;
|
283
|
+
obj->bytes_len = len;
|
284
|
+
|
285
|
+
return obj;
|
286
|
+
}
|
287
|
+
|
288
|
+
/**
|
289
|
+
* Allocates a new krypt_asn1_object given a header. For succesful encoding
|
290
|
+
* with krypt_asn1_object_encode it is expected that the value encoding will
|
291
|
+
* be added at a later point.
|
292
|
+
*
|
293
|
+
* @param header The header corresponding to the value
|
294
|
+
* @return A new header or NULL if allocation fails
|
295
|
+
*/
|
296
|
+
krypt_asn1_object *
|
297
|
+
krypt_asn1_object_new(krypt_asn1_header *header)
|
298
|
+
{
|
299
|
+
krypt_asn1_object *obj;
|
300
|
+
|
301
|
+
if (!header) return NULL;
|
302
|
+
|
303
|
+
obj = ALLOC(krypt_asn1_object);
|
304
|
+
obj->header = header;
|
305
|
+
obj->bytes = NULL;
|
306
|
+
obj->bytes_len = 0;
|
307
|
+
|
308
|
+
return obj;
|
309
|
+
}
|
310
|
+
|
311
|
+
|
312
|
+
/**
|
313
|
+
* Frees a krypt_asn1_object by freeing the header and the
|
314
|
+
* value bytes if present.
|
315
|
+
*
|
316
|
+
* @param object The krypt_asn1_object to be freed
|
317
|
+
*/
|
318
|
+
void
|
319
|
+
krypt_asn1_object_free(krypt_asn1_object *object)
|
320
|
+
{
|
321
|
+
if (!object) return;
|
322
|
+
|
323
|
+
krypt_asn1_header_free(object->header);
|
324
|
+
if (object->bytes)
|
325
|
+
xfree(object->bytes);
|
326
|
+
xfree(object);
|
327
|
+
}
|
328
|
+
|
329
|
+
int
|
330
|
+
krypt_asn1_cmp_set_of(uint8_t *s1, size_t len1,
|
331
|
+
uint8_t *s2, size_t len2, int *result)
|
332
|
+
{
|
333
|
+
size_t min, i;
|
334
|
+
krypt_asn1_header *h1 = NULL, *h2 = NULL;
|
335
|
+
binyo_instream *in1, *in2;
|
336
|
+
|
337
|
+
in1 = binyo_instream_new_bytes(s1, len1);
|
338
|
+
in2 = binyo_instream_new_bytes(s2, len2);
|
339
|
+
if (krypt_asn1_next_header(in1, &h1) != KRYPT_OK) goto error;
|
340
|
+
if (krypt_asn1_next_header(in2, &h2) != KRYPT_OK) goto error;
|
341
|
+
|
342
|
+
if (h1->tag == TAGS_END_OF_CONTENTS && h1->tag_class == TAG_CLASS_UNIVERSAL) {
|
343
|
+
*result = 1;
|
344
|
+
goto cleanup;
|
345
|
+
}
|
346
|
+
if (h2->tag == TAGS_END_OF_CONTENTS && h2->tag_class == TAG_CLASS_UNIVERSAL) {
|
347
|
+
*result = -1;
|
348
|
+
goto cleanup;
|
349
|
+
}
|
350
|
+
if (h1->tag < h2->tag) {
|
351
|
+
*result = -1;
|
352
|
+
goto cleanup;
|
353
|
+
}
|
354
|
+
if (h1->tag > h2->tag) {
|
355
|
+
*result = 1;
|
356
|
+
goto cleanup;
|
357
|
+
}
|
358
|
+
|
359
|
+
min = len1 < len2 ? len1 : len2;
|
360
|
+
|
361
|
+
for (i=0; i<min; ++i) {
|
362
|
+
if (s1[i] != s2[i]) {
|
363
|
+
*result = s1[i] < s2[i] ? -1 : 1;
|
364
|
+
goto cleanup;
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
if (len1 == len2)
|
369
|
+
*result = 0;
|
370
|
+
else
|
371
|
+
*result = len1 < len2 ? -1 : 1;
|
372
|
+
|
373
|
+
cleanup:
|
374
|
+
binyo_instream_free(in1);
|
375
|
+
binyo_instream_free(in2);
|
376
|
+
krypt_asn1_header_free(h1);
|
377
|
+
krypt_asn1_header_free(h2);
|
378
|
+
return KRYPT_OK;
|
379
|
+
error:
|
380
|
+
binyo_instream_free(in1);
|
381
|
+
binyo_instream_free(in2);
|
382
|
+
if (h1) krypt_asn1_header_free(h1);
|
383
|
+
if (h2) krypt_asn1_header_free(h2);
|
384
|
+
krypt_error_add("Error while comparing values");
|
385
|
+
return KRYPT_ERR;
|
386
|
+
}
|
387
|
+
|
388
|
+
static int
|
389
|
+
int_parse_tag(uint8_t b, binyo_instream *in, krypt_asn1_header *out)
|
390
|
+
{
|
391
|
+
if ((b & COMPLEX_TAG_MASK) == COMPLEX_TAG_MASK) {
|
392
|
+
return int_parse_complex_tag(b, in, out);
|
393
|
+
} else {
|
394
|
+
int_parse_primitive_tag(b, out);
|
395
|
+
return KRYPT_OK;
|
396
|
+
}
|
397
|
+
}
|
398
|
+
|
399
|
+
static void
|
400
|
+
int_parse_primitive_tag(uint8_t b, krypt_asn1_header *out)
|
401
|
+
{
|
402
|
+
out->tag = b & COMPLEX_TAG_MASK;
|
403
|
+
out->is_constructed = (b & CONSTRUCTED_MASK) == CONSTRUCTED_MASK;
|
404
|
+
out->tag_class = b & TAG_CLASS_PRIVATE;
|
405
|
+
out->tag_bytes = ALLOC(uint8_t);
|
406
|
+
out->tag_bytes[0] = b;
|
407
|
+
out->tag_len = 1;
|
408
|
+
}
|
409
|
+
|
410
|
+
#define int_buffer_add_byte(buf, b, out) \
|
411
|
+
do { \
|
412
|
+
if (binyo_buffer_write((buf), &(b), 1) == KRYPT_ERR) { \
|
413
|
+
binyo_buffer_free((buf)); \
|
414
|
+
return KRYPT_ERR; \
|
415
|
+
} \
|
416
|
+
} while (0)
|
417
|
+
|
418
|
+
#define int_check_tag(t, buf) \
|
419
|
+
do { \
|
420
|
+
if ((t) > KRYPT_ASN1_TAG_LIMIT) { \
|
421
|
+
binyo_buffer_free((buf)); \
|
422
|
+
krypt_error_add("Complex tag too large"); \
|
423
|
+
return KRYPT_ERR; \
|
424
|
+
} \
|
425
|
+
} while (0)
|
426
|
+
|
427
|
+
static int
|
428
|
+
int_parse_complex_tag(uint8_t b, binyo_instream *in, krypt_asn1_header *out)
|
429
|
+
{
|
430
|
+
binyo_byte_buffer *buffer;
|
431
|
+
int tag = 0;
|
432
|
+
|
433
|
+
out->is_constructed = (b & CONSTRUCTED_MASK) == CONSTRUCTED_MASK;
|
434
|
+
out->tag_class = b & TAG_CLASS_PRIVATE;
|
435
|
+
buffer = binyo_buffer_new();
|
436
|
+
int_buffer_add_byte(buffer, b, out);
|
437
|
+
|
438
|
+
int_next_byte(in, b);
|
439
|
+
|
440
|
+
if (b == INFINITE_LENGTH_MASK) {
|
441
|
+
krypt_error_add("Bits 7 to 1 of the first subsequent octet shall not be 0 for complex tag encoding");
|
442
|
+
return KRYPT_ERR;
|
443
|
+
}
|
444
|
+
|
445
|
+
while ((b & INFINITE_LENGTH_MASK) == INFINITE_LENGTH_MASK) {
|
446
|
+
int_check_tag(tag, buffer);
|
447
|
+
int_buffer_add_byte(buffer, b, out);
|
448
|
+
tag <<= CHAR_BIT_MINUS_ONE;
|
449
|
+
tag |= (b & 0x7f);
|
450
|
+
int_next_byte(in, b);
|
451
|
+
}
|
452
|
+
|
453
|
+
int_check_tag(tag, buffer);
|
454
|
+
int_buffer_add_byte(buffer, b, out);
|
455
|
+
tag <<= CHAR_BIT_MINUS_ONE;
|
456
|
+
tag |= (b & 0x7f);
|
457
|
+
out->tag = tag;
|
458
|
+
out->tag_len = binyo_buffer_get_bytes_free(buffer, &(out->tag_bytes));
|
459
|
+
return KRYPT_OK;
|
460
|
+
}
|
461
|
+
|
462
|
+
#define int_set_single_byte_length(h, b) \
|
463
|
+
do { \
|
464
|
+
(h)->length_bytes = ALLOC(uint8_t); \
|
465
|
+
(h)->length_bytes[0] = (b); \
|
466
|
+
(h)->length_len = 1; \
|
467
|
+
} while (0)
|
468
|
+
|
469
|
+
static int
|
470
|
+
int_parse_length(binyo_instream *in, krypt_asn1_header *out)
|
471
|
+
{
|
472
|
+
uint8_t b;
|
473
|
+
|
474
|
+
int_next_byte(in, b);
|
475
|
+
|
476
|
+
if (b == INFINITE_LENGTH_MASK) {
|
477
|
+
out->is_infinite = 1;
|
478
|
+
out->length = 0;
|
479
|
+
int_set_single_byte_length(out, b);
|
480
|
+
}
|
481
|
+
else if ((b & INFINITE_LENGTH_MASK) == INFINITE_LENGTH_MASK) {
|
482
|
+
out->is_infinite = 0;
|
483
|
+
return int_parse_complex_definite_length(b, in, out);
|
484
|
+
}
|
485
|
+
else {
|
486
|
+
out->is_infinite = 0;
|
487
|
+
out->length = b;
|
488
|
+
int_set_single_byte_length(out, b);
|
489
|
+
}
|
490
|
+
return KRYPT_OK;
|
491
|
+
}
|
492
|
+
|
493
|
+
#define int_check_length(l, buf) \
|
494
|
+
do { \
|
495
|
+
if ((l) > KRYPT_ASN1_LENGTH_LIMIT) { \
|
496
|
+
xfree((buf)); \
|
497
|
+
(buf) = NULL; \
|
498
|
+
krypt_error_add("Complex length too long"); \
|
499
|
+
return KRYPT_ERR; \
|
500
|
+
} \
|
501
|
+
} while (0)
|
502
|
+
|
503
|
+
|
504
|
+
static int
|
505
|
+
int_parse_complex_definite_length(uint8_t b, binyo_instream *in, krypt_asn1_header *out)
|
506
|
+
{
|
507
|
+
size_t len = 0;
|
508
|
+
size_t offset = 0;
|
509
|
+
size_t i, num_bytes;
|
510
|
+
|
511
|
+
if (b == 0xff) {
|
512
|
+
krypt_error_add("Initial octet of complex definite length shall not be 0xFF");
|
513
|
+
return KRYPT_ERR;
|
514
|
+
}
|
515
|
+
num_bytes = b & 0x7f;
|
516
|
+
|
517
|
+
out->length_bytes = ALLOC_N(uint8_t, num_bytes + 1);
|
518
|
+
out->length_bytes[offset++] = b;
|
519
|
+
|
520
|
+
for (i = num_bytes; i > 0; i--) {
|
521
|
+
int_check_length(len, out->length_bytes);
|
522
|
+
int_next_byte(in, b);
|
523
|
+
len <<= CHAR_BIT;
|
524
|
+
len |= b;
|
525
|
+
out->length_bytes[offset++] = b;
|
526
|
+
}
|
527
|
+
|
528
|
+
out->length = len;
|
529
|
+
out->length_len = num_bytes + 1;
|
530
|
+
return KRYPT_OK;
|
531
|
+
}
|
532
|
+
|
533
|
+
|
534
|
+
static int
|
535
|
+
int_parse_read_exactly(binyo_instream *in, size_t n, uint8_t **out, size_t *outlen)
|
536
|
+
{
|
537
|
+
uint8_t *ret, *p;
|
538
|
+
size_t offset = 0;
|
539
|
+
ssize_t read;
|
540
|
+
|
541
|
+
if (n == 0) {
|
542
|
+
*out = NULL;
|
543
|
+
return KRYPT_OK;
|
544
|
+
}
|
545
|
+
|
546
|
+
ret = ALLOC_N(uint8_t, n);
|
547
|
+
p = ret;
|
548
|
+
while (offset != n) {
|
549
|
+
read = binyo_instream_read(in, p, n - offset);
|
550
|
+
if (read == BINYO_IO_EOF || read == BINYO_ERR) {
|
551
|
+
xfree(ret);
|
552
|
+
*out = NULL;
|
553
|
+
if (read == BINYO_IO_EOF)
|
554
|
+
krypt_error_add("Premature EOF detected");
|
555
|
+
else
|
556
|
+
krypt_error_add("Error while reading from stream");
|
557
|
+
return KRYPT_ERR;
|
558
|
+
}
|
559
|
+
p += read;
|
560
|
+
offset += read;
|
561
|
+
}
|
562
|
+
*out = ret;
|
563
|
+
return KRYPT_OK;
|
564
|
+
}
|
565
|
+
|
566
|
+
static int
|
567
|
+
int_consume_stream(binyo_instream *in, uint8_t **out, size_t *outlen)
|
568
|
+
{
|
569
|
+
binyo_byte_buffer *out_buf;
|
570
|
+
uint8_t *in_buf;
|
571
|
+
ssize_t read;
|
572
|
+
size_t size;
|
573
|
+
|
574
|
+
in_buf = ALLOC_N(uint8_t, BINYO_IO_BUF_SIZE);
|
575
|
+
out_buf = binyo_buffer_new_size(512);
|
576
|
+
while ((read = binyo_instream_read(in, in_buf, BINYO_IO_BUF_SIZE)) >= 0) {
|
577
|
+
if (binyo_buffer_write(out_buf, in_buf, read) == BINYO_ERR) goto error;
|
578
|
+
}
|
579
|
+
if (read == BINYO_ERR) goto error;
|
580
|
+
|
581
|
+
size = binyo_buffer_get_bytes_free(out_buf, out);
|
582
|
+
xfree(in_buf);
|
583
|
+
*outlen = size;
|
584
|
+
return KRYPT_OK;
|
585
|
+
|
586
|
+
error:
|
587
|
+
xfree(in_buf);
|
588
|
+
binyo_buffer_free(out_buf);
|
589
|
+
return KRYPT_ERR;
|
590
|
+
}
|
591
|
+
|
592
|
+
#define int_determine_num_shifts(i, value, by) \
|
593
|
+
do { \
|
594
|
+
size_t tmp = (value); \
|
595
|
+
for ((i) = 0; tmp > 0; (i)++) { \
|
596
|
+
tmp >>= (by); \
|
597
|
+
} \
|
598
|
+
} while (0)
|
599
|
+
|
600
|
+
|
601
|
+
static void
|
602
|
+
int_compute_complex_tag(krypt_asn1_header *header)
|
603
|
+
{
|
604
|
+
size_t num_shifts, i;
|
605
|
+
int tmp_tag;
|
606
|
+
uint8_t b;
|
607
|
+
|
608
|
+
b = header->is_constructed ? CONSTRUCTED_MASK : 0x00;
|
609
|
+
b |= header->tag_class & 0xff;
|
610
|
+
b |= COMPLEX_TAG_MASK;
|
611
|
+
|
612
|
+
int_determine_num_shifts(num_shifts, header->tag, CHAR_BIT_MINUS_ONE);
|
613
|
+
header->tag_bytes = ALLOC_N(uint8_t, num_shifts + 1);
|
614
|
+
header->tag_bytes[0] = b;
|
615
|
+
|
616
|
+
tmp_tag = header->tag;
|
617
|
+
|
618
|
+
for (i = num_shifts; i > 0; i--) {
|
619
|
+
b = tmp_tag & 0x7f;
|
620
|
+
if (i != num_shifts)
|
621
|
+
b |= INFINITE_LENGTH_MASK;
|
622
|
+
header->tag_bytes[i] = b;
|
623
|
+
tmp_tag >>= CHAR_BIT_MINUS_ONE;
|
624
|
+
}
|
625
|
+
|
626
|
+
header->tag_len = num_shifts + 1;
|
627
|
+
}
|
628
|
+
|
629
|
+
static void
|
630
|
+
int_compute_tag(krypt_asn1_header *header)
|
631
|
+
{
|
632
|
+
if (header->tag < 31) {
|
633
|
+
uint8_t b;
|
634
|
+
b = header->is_constructed ? CONSTRUCTED_MASK : 0x00;
|
635
|
+
b |= (header->tag_class & 0xff);
|
636
|
+
b |= (header->tag & 0xff);
|
637
|
+
header->tag_bytes = ALLOC(uint8_t);
|
638
|
+
*(header->tag_bytes) = b;
|
639
|
+
header->tag_len = 1;
|
640
|
+
} else {
|
641
|
+
int_compute_complex_tag(header);
|
642
|
+
}
|
643
|
+
}
|
644
|
+
|
645
|
+
static void
|
646
|
+
int_compute_complex_length(krypt_asn1_header *header)
|
647
|
+
{
|
648
|
+
size_t num_shifts, tmp_len, i;
|
649
|
+
|
650
|
+
int_determine_num_shifts(num_shifts, header->length, CHAR_BIT);
|
651
|
+
tmp_len = header->length;
|
652
|
+
header->length_bytes = ALLOC_N(uint8_t, num_shifts + 1);
|
653
|
+
header->length_bytes[0] = num_shifts & 0xff;
|
654
|
+
header->length_bytes[0] |= INFINITE_LENGTH_MASK;
|
655
|
+
|
656
|
+
for (i = num_shifts; i > 0; i--) {
|
657
|
+
header->length_bytes[i] = tmp_len & 0xff;
|
658
|
+
tmp_len >>= CHAR_BIT;
|
659
|
+
}
|
660
|
+
|
661
|
+
header->length_len = num_shifts + 1;
|
662
|
+
}
|
663
|
+
|
664
|
+
static void
|
665
|
+
int_compute_length(krypt_asn1_header *header)
|
666
|
+
{
|
667
|
+
if (header->is_infinite) {
|
668
|
+
header->length_bytes = ALLOC(uint8_t);
|
669
|
+
*(header->length_bytes) = INFINITE_LENGTH_MASK;
|
670
|
+
header->length_len = 1;
|
671
|
+
}
|
672
|
+
else if (header->length <= 127) {
|
673
|
+
header->length_bytes = ALLOC(uint8_t);
|
674
|
+
*(header->length_bytes) = header->length & 0xFF;
|
675
|
+
header->length_len = 1;
|
676
|
+
}
|
677
|
+
else {
|
678
|
+
int_compute_complex_length(header);
|
679
|
+
}
|
680
|
+
}
|
681
|
+
|