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.
Files changed (73) hide show
  1. data/LICENSE +20 -0
  2. data/ext/krypt/core/Makefile +221 -0
  3. data/ext/krypt/core/binyo-error.h +40 -0
  4. data/ext/krypt/core/binyo-io-buffer.h +54 -0
  5. data/ext/krypt/core/binyo-io.h +131 -0
  6. data/ext/krypt/core/extconf.h +8 -0
  7. data/ext/krypt/core/extconf.rb +80 -0
  8. data/ext/krypt/core/krypt-core.c +110 -0
  9. data/ext/krypt/core/krypt-core.h +97 -0
  10. data/ext/krypt/core/krypt-core.o +0 -0
  11. data/ext/krypt/core/krypt-provider.h +86 -0
  12. data/ext/krypt/core/krypt_asn1-internal.c +681 -0
  13. data/ext/krypt/core/krypt_asn1-internal.h +117 -0
  14. data/ext/krypt/core/krypt_asn1-internal.o +0 -0
  15. data/ext/krypt/core/krypt_asn1.c +2109 -0
  16. data/ext/krypt/core/krypt_asn1.h +88 -0
  17. data/ext/krypt/core/krypt_asn1.o +0 -0
  18. data/ext/krypt/core/krypt_asn1_codec.c +973 -0
  19. data/ext/krypt/core/krypt_asn1_codec.o +0 -0
  20. data/ext/krypt/core/krypt_asn1_in_adapter.c +178 -0
  21. data/ext/krypt/core/krypt_asn1_in_adapter.o +0 -0
  22. data/ext/krypt/core/krypt_asn1_in_chunked.c +292 -0
  23. data/ext/krypt/core/krypt_asn1_in_chunked.o +0 -0
  24. data/ext/krypt/core/krypt_asn1_in_definite.c +156 -0
  25. data/ext/krypt/core/krypt_asn1_in_definite.o +0 -0
  26. data/ext/krypt/core/krypt_asn1_parser.c +592 -0
  27. data/ext/krypt/core/krypt_asn1_parser.o +0 -0
  28. data/ext/krypt/core/krypt_asn1_template-internal.h +185 -0
  29. data/ext/krypt/core/krypt_asn1_template.c +459 -0
  30. data/ext/krypt/core/krypt_asn1_template.h +56 -0
  31. data/ext/krypt/core/krypt_asn1_template.o +0 -0
  32. data/ext/krypt/core/krypt_asn1_template_encoder.c +76 -0
  33. data/ext/krypt/core/krypt_asn1_template_encoder.o +0 -0
  34. data/ext/krypt/core/krypt_asn1_template_parser.c +1176 -0
  35. data/ext/krypt/core/krypt_asn1_template_parser.o +0 -0
  36. data/ext/krypt/core/krypt_b64-internal.h +38 -0
  37. data/ext/krypt/core/krypt_b64.c +391 -0
  38. data/ext/krypt/core/krypt_b64.h +41 -0
  39. data/ext/krypt/core/krypt_b64.o +0 -0
  40. data/ext/krypt/core/krypt_digest.c +391 -0
  41. data/ext/krypt/core/krypt_digest.h +51 -0
  42. data/ext/krypt/core/krypt_digest.o +0 -0
  43. data/ext/krypt/core/krypt_error.c +221 -0
  44. data/ext/krypt/core/krypt_error.h +46 -0
  45. data/ext/krypt/core/krypt_error.o +0 -0
  46. data/ext/krypt/core/krypt_hex-internal.h +36 -0
  47. data/ext/krypt/core/krypt_hex.c +255 -0
  48. data/ext/krypt/core/krypt_hex.h +41 -0
  49. data/ext/krypt/core/krypt_hex.o +0 -0
  50. data/ext/krypt/core/krypt_io.c +65 -0
  51. data/ext/krypt/core/krypt_io.h +56 -0
  52. data/ext/krypt/core/krypt_io.o +0 -0
  53. data/ext/krypt/core/krypt_io_in_pem.c +397 -0
  54. data/ext/krypt/core/krypt_io_in_pem.o +0 -0
  55. data/ext/krypt/core/krypt_missing.c +238 -0
  56. data/ext/krypt/core/krypt_missing.h +62 -0
  57. data/ext/krypt/core/krypt_missing.o +0 -0
  58. data/ext/krypt/core/krypt_pem.c +171 -0
  59. data/ext/krypt/core/krypt_pem.o +0 -0
  60. data/ext/krypt/core/krypt_provider-internal.h +40 -0
  61. data/ext/krypt/core/krypt_provider.c +136 -0
  62. data/ext/krypt/core/krypt_provider.o +0 -0
  63. data/ext/krypt/core/kryptcore.so +0 -0
  64. data/ext/krypt/core/mkmf.log +130 -0
  65. data/lib/krypt-core/version.rb +3 -0
  66. data/lib/krypt-core.rb +35 -0
  67. data/lib/kryptcore.so +0 -0
  68. data/spec/README +2 -0
  69. data/test/README +2 -0
  70. data/test/res/certificate.cer +0 -0
  71. data/test/resources.rb +48 -0
  72. data/test/scratch.rb +17 -0
  73. 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
+