krypt-core 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+