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,2109 @@
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 "krypt-core.h"
30
+ #include "krypt_asn1-internal.h"
31
+
32
+ VALUE mKryptASN1;
33
+ VALUE eKryptASN1Error, eKryptASN1ParseError, eKryptASN1SerializeError;
34
+
35
+ VALUE cKryptASN1Data;
36
+ VALUE cKryptASN1Primitive;
37
+ VALUE cKryptASN1Constructive;
38
+
39
+ /* PRIMITIVE */
40
+ VALUE cKryptASN1EndOfContents;
41
+ VALUE cKryptASN1Boolean; /* BOOLEAN */
42
+ VALUE cKryptASN1Integer, cKryptASN1Enumerated; /* INTEGER */
43
+ VALUE cKryptASN1BitString; /* BIT STRING */
44
+ VALUE cKryptASN1OctetString, cKryptASN1UTF8String; /* STRINGs */
45
+ VALUE cKryptASN1NumericString, cKryptASN1PrintableString;
46
+ VALUE cKryptASN1T61String, cKryptASN1VideotexString;
47
+ VALUE cKryptASN1IA5String, cKryptASN1GraphicString;
48
+ VALUE cKryptASN1ISO64String, cKryptASN1GeneralString;
49
+ VALUE cKryptASN1UniversalString, cKryptASN1BMPString;
50
+ VALUE cKryptASN1Null; /* NULL */
51
+ VALUE cKryptASN1ObjectId; /* OBJECT IDENTIFIER */
52
+ VALUE cKryptASN1UTCTime, cKryptASN1GeneralizedTime; /* TIME */
53
+
54
+ /* CONSTRUCTIVE */
55
+ VALUE cKryptASN1Sequence, cKryptASN1Set;
56
+
57
+ ID sKrypt_TC_UNIVERSAL, sKrypt_TC_APPLICATION, sKrypt_TC_CONTEXT_SPECIFIC, sKrypt_TC_PRIVATE;
58
+ ID sKrypt_TC_EXPLICIT, sKrypt_TC_IMPLICIT;
59
+
60
+ ID sKrypt_IV_TAG, sKrypt_IV_TAG_CLASS, sKrypt_IV_INF_LEN, sKrypt_IV_UNUSED_BITS;
61
+ ID sKrypt_IV_VALUE;
62
+
63
+ typedef struct krypt_asn1_info_st {
64
+ const char *name;
65
+ VALUE *klass;
66
+ } krypt_asn1_info;
67
+
68
+ static krypt_asn1_info krypt_asn1_infos[] = {
69
+ { "END_OF_CONTENTS", &cKryptASN1EndOfContents, }, /* 0 */
70
+ { "BOOLEAN", &cKryptASN1Boolean, }, /* 1 */
71
+ { "INTEGER", &cKryptASN1Integer, }, /* 2 */
72
+ { "BIT_STRING", &cKryptASN1BitString, }, /* 3 */
73
+ { "OCTET_STRING", &cKryptASN1OctetString, }, /* 4 */
74
+ { "NULL", &cKryptASN1Null, }, /* 5 */
75
+ { "OBJECT_ID", &cKryptASN1ObjectId, }, /* 6 */
76
+ { "OBJECT_DESCRIPTOR", NULL, }, /* 7 */
77
+ { "EXTERNAL", NULL, }, /* 8 */
78
+ { "REAL", NULL, }, /* 9 */
79
+ { "ENUMERATED", &cKryptASN1Enumerated, }, /* 10 */
80
+ { "EMBEDDED_PDV", NULL, }, /* 11 */
81
+ { "UTF8_STRING", &cKryptASN1UTF8String, }, /* 12 */
82
+ { "RELATIVE_OID", NULL, }, /* 13 */
83
+ { "[UNIVERSAL 14]", NULL, }, /* 14 */
84
+ { "[UNIVERSAL 15]", NULL, }, /* 15 */
85
+ { "SEQUENCE", &cKryptASN1Sequence, }, /* 16 */
86
+ { "SET", &cKryptASN1Set, }, /* 17 */
87
+ { "NUMERIC_STRING", &cKryptASN1NumericString, }, /* 18 */
88
+ { "PRINTABLE_STRING", &cKryptASN1PrintableString, }, /* 19 */
89
+ { "T61_STRING", &cKryptASN1T61String, }, /* 20 */
90
+ { "VIDEOTEX_STRING", &cKryptASN1VideotexString, }, /* 21 */
91
+ { "IA5_STRING", &cKryptASN1IA5String, }, /* 22 */
92
+ { "UTC_TIME", &cKryptASN1UTCTime, }, /* 23 */
93
+ { "GENERALIZED_TIME", &cKryptASN1GeneralizedTime, }, /* 24 */
94
+ { "GRAPHIC_STRING", &cKryptASN1GraphicString, }, /* 25 */
95
+ { "ISO64_STRING", &cKryptASN1ISO64String, }, /* 26 */
96
+ { "GENERAL_STRING", &cKryptASN1GeneralString, }, /* 27 */
97
+ { "UNIVERSAL_STRING", &cKryptASN1UniversalString, }, /* 28 */
98
+ { "CHARACTER_STRING", NULL, }, /* 29 */
99
+ { "BMP_STRING", &cKryptASN1BMPString, }, /* 30 */
100
+ };
101
+
102
+ static int krypt_asn1_infos_size = (sizeof(krypt_asn1_infos)/sizeof(krypt_asn1_infos[0]));
103
+
104
+ #define ASN1DATA_DECODED (1 << 0)
105
+ #define ASN1DATA_EXPLICIT (1 << 1)
106
+ #define ASN1DATA_MODIFIED (1 << 2)
107
+
108
+ struct krypt_asn1_data_st;
109
+ typedef struct krypt_asn1_data_st krypt_asn1_data;
110
+ typedef void (*krypt_asn1_update_cb)(krypt_asn1_data *);
111
+
112
+ struct krypt_asn1_data_st {
113
+ krypt_asn1_object *object;
114
+ krypt_asn1_update_cb update_cb;
115
+ krypt_asn1_codec *codec;
116
+ int flags;
117
+ int default_tag;
118
+ };
119
+
120
+ static krypt_asn1_codec *
121
+ int_codec_for(krypt_asn1_object *object)
122
+ {
123
+ krypt_asn1_codec *codec = NULL;
124
+ int tag = object->header->tag;
125
+
126
+ if (tag < 31 && object->header->tag_class == TAG_CLASS_UNIVERSAL)
127
+ codec = &krypt_asn1_codecs[tag];
128
+ if (!codec)
129
+ codec = &KRYPT_DEFAULT_CODEC;
130
+
131
+ return codec;
132
+ }
133
+
134
+ static krypt_asn1_data *
135
+ int_asn1_data_new(krypt_asn1_object *object)
136
+ {
137
+ krypt_asn1_data *ret;
138
+
139
+ ret = ALLOC(krypt_asn1_data);
140
+ ret->object = object;
141
+ ret->update_cb = NULL;
142
+ ret->codec = int_codec_for(object);
143
+ ret->flags = ASN1DATA_DECODED; /* only overwritten by parsed values */
144
+ ret->default_tag = -1;
145
+ return ret;
146
+ }
147
+
148
+ static void
149
+ int_asn1_data_free(krypt_asn1_data *data)
150
+ {
151
+ if (!data) return;
152
+ krypt_asn1_object_free(data->object);
153
+ xfree(data);
154
+ }
155
+
156
+ #define int_asn1_data_set(klass, obj, data) \
157
+ do { \
158
+ if (!(data)) { \
159
+ rb_raise(eKryptError, "Uninitialized krypt_asn1_data"); \
160
+ } \
161
+ (obj) = Data_Wrap_Struct((klass), 0, int_asn1_data_free, (data)); \
162
+ } while (0)
163
+
164
+ #define int_asn1_data_get(obj, data) \
165
+ do { \
166
+ Data_Get_Struct((obj), krypt_asn1_data, (data)); \
167
+ if (!(data)) { \
168
+ rb_raise(eKryptError, "Uninitialized krypt_asn1_data"); \
169
+ } \
170
+ } while (0)
171
+
172
+ #define int_asn1_data_get_tag(o) rb_ivar_get((o), sKrypt_IV_TAG)
173
+ #define int_asn1_data_get_tag_class(o) rb_ivar_get((o), sKrypt_IV_TAG_CLASS)
174
+ #define int_asn1_data_get_infinite_length(o) rb_ivar_get((o), sKrypt_IV_INF_LEN)
175
+ #define int_asn1_data_get_value(o) rb_ivar_get((o), sKrypt_IV_VALUE)
176
+
177
+ #define int_asn1_data_set_tag(o, v) rb_ivar_set((o), sKrypt_IV_TAG, (v))
178
+ #define int_asn1_data_set_tag_class(o, v) rb_ivar_set((o), sKrypt_IV_TAG_CLASS, (v))
179
+ #define int_asn1_data_set_infinite_length(o, v) rb_ivar_set((o), sKrypt_IV_INF_LEN, (v))
180
+ #define int_asn1_data_set_value(o, v) rb_ivar_set((o), sKrypt_IV_VALUE, (v))
181
+
182
+ #define int_asn1_data_is_decoded(o) (((o)->flags & ASN1DATA_DECODED) == ASN1DATA_DECODED)
183
+ #define int_asn1_data_is_explicit(o) (((o)->flags & ASN1DATA_EXPLICIT) == ASN1DATA_EXPLICIT)
184
+ #define int_asn1_data_is_modified(o) (((o)->flags & ASN1DATA_MODIFIED) == ASN1DATA_MODIFIED)
185
+ #define int_asn1_data_set_decoded(o, b) \
186
+ do { \
187
+ if (b) { \
188
+ (o)->flags |= ASN1DATA_DECODED; \
189
+ } else { \
190
+ (o)->flags &= ~ASN1DATA_DECODED; \
191
+ } \
192
+ } while (0)
193
+ #define int_asn1_data_set_explicit(o, b) \
194
+ do { \
195
+ if (b) { \
196
+ (o)->flags |= ASN1DATA_EXPLICIT; \
197
+ } else { \
198
+ (o)->flags &= ~ASN1DATA_EXPLICIT; \
199
+ } \
200
+ } while (0)
201
+ #define int_asn1_data_set_modified(o, b) \
202
+ do { \
203
+ if (b) { \
204
+ (o)->flags |= ASN1DATA_MODIFIED; \
205
+ } else { \
206
+ (o)->flags &= ~ASN1DATA_MODIFIED; \
207
+ } \
208
+ } while (0)
209
+
210
+ /* Declaration of en-/decode callbacks */
211
+ static int int_asn1_data_value_decode(VALUE self, krypt_asn1_data *data, VALUE *out);
212
+ static int int_asn1_cons_value_decode(VALUE self, krypt_asn1_data *data, VALUE *out);
213
+ static int int_asn1_prim_value_decode(VALUE self, krypt_asn1_data *data, VALUE *out);
214
+
215
+ static int int_asn1_data_encode_to(VALUE self, binyo_outstream *out, VALUE value, krypt_asn1_data *data);
216
+ static int int_asn1_cons_encode_to(VALUE self, binyo_outstream *out, VALUE value, krypt_asn1_data *data);
217
+ static int int_asn1_prim_encode_to(VALUE self, binyo_outstream *out, VALUE value, krypt_asn1_data *data);
218
+
219
+ static void
220
+ int_handle_class_specifics(VALUE self, krypt_asn1_header *header)
221
+ {
222
+ if (header->tag_class == TAG_CLASS_UNIVERSAL) {
223
+ switch (header->tag) {
224
+ case TAGS_BIT_STRING:
225
+ rb_ivar_set(self, sKrypt_IV_UNUSED_BITS, INT2NUM(0));
226
+ break;
227
+ default:
228
+ break;
229
+ }
230
+ }
231
+ }
232
+
233
+ static VALUE
234
+ int_determine_class_and_default_tag(krypt_asn1_data *data)
235
+ {
236
+ krypt_asn1_header *header = data->object->header;
237
+
238
+ if (header->tag_class == TAG_CLASS_UNIVERSAL) {
239
+ if (header->tag > 30) {
240
+ krypt_error_add("Universal tag too large: %d", header->tag);
241
+ return Qnil;
242
+ }
243
+ if (!krypt_asn1_infos[header->tag].klass) {
244
+ if (header->is_constructed)
245
+ return cKryptASN1Constructive;
246
+ else
247
+ return cKryptASN1Data;
248
+ }
249
+ data->default_tag = header->tag;
250
+ return *(krypt_asn1_infos[header->tag].klass);
251
+ }
252
+ else {
253
+ return header->is_constructed ? cKryptASN1Constructive : cKryptASN1Data;
254
+ }
255
+ }
256
+
257
+ /* This initializer is used with freshly parsed values */
258
+ static VALUE
259
+ krypt_asn1_data_new(binyo_instream *in, krypt_asn1_header *header)
260
+ {
261
+ VALUE obj;
262
+ VALUE klass;
263
+ ID tag_class;
264
+ krypt_asn1_data *data;
265
+ krypt_asn1_object *encoding;
266
+ uint8_t *value = NULL;
267
+ size_t value_len;
268
+
269
+ if (krypt_asn1_get_value(in, header, &value, &value_len) == KRYPT_ERR)
270
+ return Qnil;
271
+
272
+ encoding = krypt_asn1_object_new_value(header, value, value_len);
273
+ data = int_asn1_data_new(encoding);
274
+ int_asn1_data_set_decoded(data, 0);
275
+ klass = int_determine_class_and_default_tag(data);
276
+ if (NIL_P(klass)) goto error;
277
+ int_asn1_data_set(klass, obj, data);
278
+
279
+ int_asn1_data_set_tag(obj, INT2NUM(header->tag));
280
+ if (!(tag_class = krypt_asn1_tag_class_for_int(header->tag_class))) goto error;
281
+ int_asn1_data_set_tag_class(obj, ID2SYM(tag_class));
282
+ int_asn1_data_set_infinite_length(obj, header->is_infinite ? Qtrue : Qfalse);
283
+
284
+ int_handle_class_specifics(obj, header);
285
+
286
+ return obj;
287
+
288
+ error:
289
+ xfree(data->object->bytes);
290
+ xfree(data->object);
291
+ xfree(data); /*header will be freed by caller */
292
+ return Qnil;
293
+ }
294
+
295
+ /* Initializer section for ASN1Data created from scratch */
296
+ static VALUE
297
+ krypt_asn1_data_alloc(VALUE klass)
298
+ {
299
+ return Data_Wrap_Struct(klass, 0, int_asn1_data_free, 0);
300
+ }
301
+
302
+ /* Generic helper for initialization */
303
+ static void
304
+ int_asn1_data_initialize(VALUE self,
305
+ int tag,
306
+ int tag_class,
307
+ int is_constructed,
308
+ int is_infinite)
309
+ {
310
+ krypt_asn1_data *data;
311
+ krypt_asn1_object *object;
312
+ krypt_asn1_header *header;
313
+
314
+ if (DATA_PTR(self))
315
+ rb_raise(eKryptASN1Error, "ASN1Data already initialized");
316
+ header = krypt_asn1_header_new();
317
+ header->tag = tag;
318
+ header->tag_class = tag_class;
319
+ header->is_constructed = is_constructed;
320
+ header->is_infinite = is_infinite;
321
+ object = krypt_asn1_object_new(header);
322
+ data = int_asn1_data_new(object);
323
+ if (tag_class == TAG_CLASS_UNIVERSAL)
324
+ data->codec = int_codec_for(object);
325
+ DATA_PTR(self) = data;
326
+ }
327
+
328
+ #define int_validate_tag_and_class(t, tc) \
329
+ do { \
330
+ if (!SYMBOL_P((tc))) \
331
+ rb_raise(eKryptASN1Error, "Tag class must be a Symbol"); \
332
+ if (!FIXNUM_P((t))) \
333
+ rb_raise(eKryptASN1Error, "Tag must be a Number"); \
334
+ } while (0)
335
+
336
+ /** ASN1Data can dynamically change its codec while
337
+ * ASN1Primitive and ASN1Constructive and its
338
+ * sub classes can not. */
339
+ static void
340
+ int_asn1_data_update_cb(krypt_asn1_data *data)
341
+ {
342
+ if (!data->object->header->is_constructed)
343
+ data->codec = int_codec_for(data->object);
344
+ }
345
+
346
+ /* Used by non-UNIVERSAL values */
347
+ /*
348
+ * call-seq:
349
+ * ASN1Data.new(value, tag, tag_class) -> ASN1Data
350
+ *
351
+ * * +value+: the value to be associated. See Primitive for the mappings
352
+ * between ASN.1 types and Ruby types.
353
+ * * +tag+: a +Number+ representing this value's tag.
354
+ * * +tag_class+: a +Symbol+ representing one of the four valid tag classes
355
+ * +:UNIVERSAL+, +:CONTEXT_SPECIFIC+, +:APPLICATION+ or +:PRIVATE+.
356
+ *
357
+ * Creates an ASN1Data from scratch.
358
+ */
359
+ static VALUE
360
+ krypt_asn1_data_initialize(VALUE self, VALUE value, VALUE vtag, VALUE vtag_class)
361
+ {
362
+ ID stag_class;
363
+ int tag, tag_class, is_constructed;
364
+ krypt_asn1_data *data;
365
+
366
+ int_validate_tag_and_class(vtag, vtag_class);
367
+ tag = NUM2INT(vtag);
368
+ stag_class = SYM2ID(vtag_class);
369
+ if (stag_class == sKrypt_TC_EXPLICIT)
370
+ rb_raise(eKryptASN1Error, "Explicit tagging is only supported for explicit UNIVERSAL sub classes of ASN1Data");
371
+ if (stag_class == sKrypt_TC_UNIVERSAL && tag > 30)
372
+ rb_raise(eKryptASN1Error, "Tag too large for UNIVERSAL tag class");
373
+ if ((tag_class = krypt_asn1_tag_class_for_id(stag_class)) == KRYPT_ERR)
374
+ rb_raise(eKryptASN1Error, "Unknown tag class");
375
+ is_constructed = rb_respond_to(value, sKrypt_ID_EACH);
376
+
377
+ int_asn1_data_initialize(self, tag, tag_class, is_constructed, 0);
378
+
379
+ int_asn1_data_get(self, data);
380
+ data->update_cb = int_asn1_data_update_cb;
381
+
382
+ int_asn1_data_set_tag(self, vtag);
383
+ int_asn1_data_set_tag_class(self, vtag_class);
384
+ int_asn1_data_set_infinite_length(self, Qfalse);
385
+ int_asn1_data_set_value(self, value);
386
+
387
+ int_asn1_data_set_modified(data, 1); /* newly created is modified by default */
388
+
389
+ return self;
390
+ }
391
+
392
+ static VALUE int_asn1_default_initialize(VALUE self, VALUE value, VALUE vtag, int default_tag, VALUE vtag_class);
393
+
394
+ /* Default helper for all UNIVERSAL values */
395
+ static VALUE
396
+ int_asn1_default_initialize(VALUE self,
397
+ VALUE value,
398
+ VALUE vtag,
399
+ int default_tag,
400
+ VALUE vtag_class)
401
+ {
402
+ ID stag_class;
403
+ int tag, tag_class, is_constructed;
404
+ krypt_asn1_data *data;
405
+
406
+ int_validate_tag_and_class(vtag, vtag_class);
407
+ tag = NUM2INT(vtag);
408
+ stag_class = SYM2ID(vtag_class);
409
+ if (stag_class == sKrypt_TC_UNIVERSAL && tag > 30)
410
+ rb_raise(eKryptASN1Error, "Tag too large for UNIVERSAL tag class");
411
+ if ((tag_class = krypt_asn1_tag_class_for_id(stag_class)) == KRYPT_ERR)
412
+ rb_raise(eKryptASN1Error, "Unknown tag class");
413
+
414
+ is_constructed = rb_respond_to(value, sKrypt_ID_EACH);
415
+
416
+ int_asn1_data_initialize(self,
417
+ tag,
418
+ tag_class,
419
+ is_constructed,
420
+ 0);
421
+
422
+ int_asn1_data_get(self, data);
423
+
424
+ if (stag_class == sKrypt_TC_EXPLICIT)
425
+ int_asn1_data_set_explicit(data, 1);
426
+
427
+ /* Override default behavior to support tag classes other than UNIVERSAL */
428
+ if (default_tag <= 30) {
429
+ data->codec = &krypt_asn1_codecs[default_tag];
430
+ data->default_tag = default_tag;
431
+ }
432
+
433
+ int_asn1_data_set_tag(self, vtag);
434
+ int_asn1_data_set_tag_class(self, vtag_class);
435
+ int_asn1_data_set_infinite_length(self, Qfalse);
436
+ int_asn1_data_set_value(self, value);
437
+
438
+ int_asn1_data_set_modified(data, 1); /* newly created is modified by default */
439
+
440
+ return self;
441
+ }
442
+
443
+ #define int_validate_args(tag, tc, argc, defaulttag) \
444
+ do { \
445
+ if (!NIL_P((tc))) { \
446
+ if (NIL_P((tag))) \
447
+ rb_raise(eKryptASN1Error, "Tag must be specified if tag class is"); \
448
+ if (!SYMBOL_P((tc))) \
449
+ rb_raise(eKryptASN1Error, "Tag class must be a Symbol"); \
450
+ } \
451
+ if (NIL_P((tc))) { \
452
+ if ((argc) == 3) \
453
+ rb_raise(eKryptASN1Error, "Tag class must be a Symbol"); \
454
+ if (NIL_P((tag))) \
455
+ (tc) = ID2SYM(sKrypt_TC_UNIVERSAL); \
456
+ else \
457
+ (tc) = ID2SYM(sKrypt_TC_CONTEXT_SPECIFIC); \
458
+ } \
459
+ if (NIL_P((tag))) { \
460
+ (tag) = INT2NUM((defaulttag)); \
461
+ } \
462
+ else { \
463
+ if (!FIXNUM_P((tag))) \
464
+ rb_raise(eKryptASN1Error, "Tag must be a Number"); \
465
+ } \
466
+ } while (0)
467
+
468
+ /* Special treatment for EOC: no-arg constructor */
469
+ static VALUE
470
+ krypt_asn1_end_of_contents_initialize(int argc, VALUE *argv, VALUE self)
471
+ {
472
+ VALUE value;
473
+ VALUE tag;
474
+ VALUE tag_class;
475
+
476
+ if (argc == 0) {
477
+ value = Qnil;
478
+ }
479
+ else {
480
+ rb_scan_args(argc, argv, "10", &value);
481
+ if(!NIL_P(value))
482
+ rb_raise(rb_eArgError, "Value must be nil for END_OF_CONTENTS");
483
+ }
484
+
485
+ tag = INT2NUM(TAGS_END_OF_CONTENTS);
486
+ tag_class = ID2SYM(sKrypt_TC_UNIVERSAL);
487
+ return int_asn1_default_initialize(self,
488
+ value,
489
+ tag,
490
+ TAGS_END_OF_CONTENTS,
491
+ tag_class);
492
+ }
493
+
494
+ static VALUE
495
+ int_asn1_end_of_contents_new_instance(void)
496
+ {
497
+ VALUE eoc;
498
+
499
+ eoc = rb_obj_alloc(cKryptASN1EndOfContents);
500
+ return krypt_asn1_end_of_contents_initialize(0, NULL, eoc);
501
+ }
502
+
503
+ /* Special treatment for NULL: no-arg constructor */
504
+ static VALUE
505
+ krypt_asn1_null_initialize(int argc, VALUE *argv, VALUE self)
506
+ {
507
+ VALUE value;
508
+ VALUE tag;
509
+ VALUE tag_class;
510
+ if (argc == 0) {
511
+ value = Qnil;
512
+ tag = INT2NUM(TAGS_NULL);
513
+ tag_class = ID2SYM(sKrypt_TC_UNIVERSAL);
514
+ }
515
+ else {
516
+ rb_scan_args(argc, argv, "12", &value, &tag, &tag_class);
517
+ int_validate_args(tag, tag_class, argc, TAGS_NULL);
518
+ if (!NIL_P(value))
519
+ rb_raise(rb_eArgError, "Value must be nil for NULL");
520
+ }
521
+
522
+ return int_asn1_default_initialize(self,
523
+ value,
524
+ tag,
525
+ TAGS_NULL,
526
+ tag_class);
527
+ }
528
+
529
+ /* Special treatment for BIT_STRING: set @unused_bits */
530
+ static VALUE
531
+ krypt_asn1_bit_string_initialize(int argc, VALUE *argv, VALUE self)
532
+ {
533
+ VALUE value;
534
+ VALUE tag;
535
+ VALUE tag_class;
536
+ rb_scan_args(argc, argv, "12", &value, &tag, &tag_class);
537
+ int_validate_args(tag, tag_class, argc, TAGS_BIT_STRING);
538
+
539
+ self = int_asn1_default_initialize(self,
540
+ value,
541
+ tag,
542
+ TAGS_BIT_STRING,
543
+ tag_class);
544
+
545
+ rb_ivar_set(self, sKrypt_IV_UNUSED_BITS, INT2NUM(0));
546
+
547
+ return self;
548
+ }
549
+
550
+ #define KRYPT_ASN1_DEFINE_CTOR(klass, t) \
551
+ static VALUE \
552
+ krypt_asn1_##klass##_initialize(int argc, VALUE *argv, VALUE self) \
553
+ { \
554
+ VALUE value, tag, tag_class; \
555
+ rb_scan_args(argc, argv, "12", &value, &tag, &tag_class); \
556
+ int_validate_args(tag, tag_class, argc, t); \
557
+ return int_asn1_default_initialize(self, value, tag, (t), tag_class); \
558
+ }
559
+
560
+ KRYPT_ASN1_DEFINE_CTOR(boolean, TAGS_BOOLEAN )
561
+ KRYPT_ASN1_DEFINE_CTOR(integer, TAGS_INTEGER )
562
+ KRYPT_ASN1_DEFINE_CTOR(enumerated, TAGS_ENUMERATED )
563
+ KRYPT_ASN1_DEFINE_CTOR(octet_string, TAGS_OCTET_STRING )
564
+ KRYPT_ASN1_DEFINE_CTOR(utf8_string, TAGS_UTF8_STRING )
565
+ KRYPT_ASN1_DEFINE_CTOR(numeric_string, TAGS_NUMERIC_STRING )
566
+ KRYPT_ASN1_DEFINE_CTOR(printable_string, TAGS_PRINTABLE_STRING )
567
+ KRYPT_ASN1_DEFINE_CTOR(t61_string, TAGS_T61_STRING )
568
+ KRYPT_ASN1_DEFINE_CTOR(videotex_string, TAGS_VIDEOTEX_STRING )
569
+ KRYPT_ASN1_DEFINE_CTOR(ia5_string, TAGS_IA5_STRING )
570
+ KRYPT_ASN1_DEFINE_CTOR(graphic_string, TAGS_GRAPHIC_STRING )
571
+ KRYPT_ASN1_DEFINE_CTOR(iso64_string, TAGS_ISO64_STRING )
572
+ KRYPT_ASN1_DEFINE_CTOR(general_string, TAGS_GENERAL_STRING )
573
+ KRYPT_ASN1_DEFINE_CTOR(universal_string, TAGS_UNIVERSAL_STRING )
574
+ KRYPT_ASN1_DEFINE_CTOR(bmp_string, TAGS_BMP_STRING )
575
+ KRYPT_ASN1_DEFINE_CTOR(object_id, TAGS_OBJECT_ID )
576
+ KRYPT_ASN1_DEFINE_CTOR(utc_time, TAGS_UTC_TIME )
577
+ KRYPT_ASN1_DEFINE_CTOR(generalized_time, TAGS_GENERALIZED_TIME )
578
+
579
+ KRYPT_ASN1_DEFINE_CTOR(sequence, TAGS_SEQUENCE )
580
+ KRYPT_ASN1_DEFINE_CTOR(set, TAGS_SET )
581
+
582
+ /* End initializer section for ASN1Data created from scratch */
583
+
584
+ /* ASN1Data methods */
585
+
586
+ #define int_invalidate_tag(h) \
587
+ do { \
588
+ if ((h)->tag_bytes) \
589
+ xfree((h)->tag_bytes); \
590
+ (h)->tag_bytes = NULL; \
591
+ (h)->tag_len = 0; \
592
+ } while (0)
593
+
594
+ #define int_invalidate_length(h) \
595
+ do { \
596
+ if ((h)->length_bytes) \
597
+ xfree((h)->length_bytes); \
598
+ (h)->length_bytes = NULL; \
599
+ (h)->length_len = 0; \
600
+ (h)->length = 0; \
601
+ } while (0)
602
+
603
+ #define int_invalidate_value(o) \
604
+ do { \
605
+ if ((o)->bytes) \
606
+ xfree((o)->bytes); \
607
+ (o)->bytes = NULL; \
608
+ (o)->bytes_len = 0; \
609
+ int_invalidate_length((o)->header); \
610
+ } while (0)
611
+
612
+ /*
613
+ * call-seq:
614
+ * asn1.tag -> Number
615
+ *
616
+ * Returns a +Number+ representing the tag number of this ASN1Data.
617
+ * Never +nil+.
618
+ */
619
+ static VALUE
620
+ krypt_asn1_data_get_tag(VALUE self)
621
+ {
622
+ return int_asn1_data_get_tag(self);
623
+ }
624
+
625
+ /*
626
+ * call-seq:
627
+ * asn1.tag=(number) -> Number
628
+ *
629
+ * * +number+: a +Number+ representing the tag number of this ASN1Data.
630
+ * Must not be +nil+.
631
+ */
632
+ static VALUE
633
+ krypt_asn1_data_set_tag(VALUE self, VALUE tag)
634
+ {
635
+ krypt_asn1_data *data;
636
+ krypt_asn1_header *header;
637
+ int new_tag;
638
+
639
+ int_asn1_data_get(self, data);
640
+
641
+ header = data->object->header;
642
+ new_tag = NUM2INT(tag);
643
+ if (header->tag == new_tag)
644
+ return tag;
645
+
646
+ header->tag = new_tag;
647
+ int_invalidate_tag(header);
648
+ if (data->update_cb)
649
+ data->update_cb(data);
650
+
651
+ int_asn1_data_set_modified(data, 1);
652
+ int_asn1_data_set_tag(self, tag);
653
+
654
+ return tag;
655
+ }
656
+
657
+ /*
658
+ * call-seq:
659
+ * asn1.tag_class -> Symbol
660
+ *
661
+ * Returns a +Symbol+ representing the tag class of this ASN1Data.
662
+ * Never +nil+. See ASN1Data for possible values.
663
+ */
664
+ static VALUE
665
+ krypt_asn1_data_get_tag_class(VALUE self)
666
+ {
667
+ return int_asn1_data_get_tag_class(self);
668
+ }
669
+
670
+ static int int_asn1_decode_value(VALUE self);
671
+
672
+ static int
673
+ int_asn1_handle_explicit_tagging(VALUE self, krypt_asn1_data *data, ID new_tc)
674
+ {
675
+ int old_explicit;
676
+ int invalidate_value = 0;
677
+
678
+ old_explicit = int_asn1_data_is_explicit(data);
679
+ if (new_tc == sKrypt_TC_EXPLICIT && old_explicit == 0) {
680
+ invalidate_value = 1;
681
+ int_asn1_data_set_explicit(data, 1);
682
+ }
683
+ if (new_tc != sKrypt_TC_EXPLICIT && old_explicit == 1) {
684
+ invalidate_value = 1;
685
+ int_asn1_data_set_explicit(data, 0);
686
+ }
687
+
688
+ if (invalidate_value) {
689
+ if (!int_asn1_data_is_decoded(data)) {
690
+ if(int_asn1_decode_value(self) == KRYPT_ERR) return KRYPT_ERR;
691
+ }
692
+ int_invalidate_value(data->object);
693
+ }
694
+ return KRYPT_OK;
695
+ }
696
+
697
+ /*
698
+ * call-seq:
699
+ * asn1.tag_class=(sym) -> Symbol
700
+ *
701
+ * * +sym+: A +Symbol+ representing the tag class of this ASN1Data.
702
+ * Must not be +nil+. See ASN1Data for possible values.
703
+ */
704
+ static VALUE
705
+ krypt_asn1_data_set_tag_class(VALUE self, VALUE tag_class)
706
+ {
707
+ krypt_asn1_data *data;
708
+ krypt_asn1_header *header;
709
+ int new_tag_class;
710
+ ID new_tc, old_tc;
711
+
712
+ int_asn1_data_get(self, data);
713
+
714
+ new_tc = SYM2ID(tag_class);
715
+ old_tc = SYM2ID(int_asn1_data_get_tag_class(self));
716
+ if (new_tc == old_tc)
717
+ return tag_class;
718
+ if (new_tc == sKrypt_TC_EXPLICIT && data->default_tag == -1)
719
+ rb_raise(eKryptASN1Error, "Cannot explicitly tag value with unknown default tag");
720
+
721
+ header = data->object->header;
722
+ if ((new_tag_class = krypt_asn1_tag_class_for_id(new_tc)) == KRYPT_ERR)
723
+ rb_raise(eKryptASN1Error, "Cannot set tag class");
724
+
725
+ header->tag_class = new_tag_class;
726
+ int_invalidate_tag(header);
727
+
728
+ if (data->update_cb)
729
+ data->update_cb(data);
730
+
731
+ if (int_asn1_handle_explicit_tagging(self, data, new_tc) == KRYPT_ERR)
732
+ rb_raise(eKryptASN1Error, "Tagging explicitly failed");
733
+
734
+ int_asn1_data_set_modified(data, 1);
735
+ int_asn1_data_set_tag_class(self, tag_class);
736
+
737
+ return tag_class;
738
+ }
739
+
740
+ /*
741
+ * call-seq:
742
+ * asn1.infinite_length -> bool
743
+ *
744
+ * Returns either true or false, depending on whether the value
745
+ * is to be or was encoded using infinite length. See
746
+ * ASN1Data#infinite_length= for details.
747
+ */
748
+ static VALUE
749
+ krypt_asn1_data_get_inf_length(VALUE self)
750
+ {
751
+ return int_asn1_data_get_infinite_length(self);
752
+ }
753
+
754
+ /*
755
+ * call-seq:
756
+ * asn1.infinite_length=(bool) -> bool
757
+ *
758
+ * * +bool+: either true or false, depending on whether the value shall be
759
+ * encoded using infinite length encoding or not
760
+ *
761
+ * Set a +Boolean+ indicating whether the encoding shall be infinite
762
+ * length or not.
763
+ * In DER, every value has a finite length associated with it. But in
764
+ * scenarios where large amounts of data need to be transferred, it
765
+ * might be desirable to have some kind of streaming support available.
766
+ * For example, huge OCTET STRINGs are preferably sent in smaller-sized
767
+ * chunks, each at a time.
768
+ * This is possible in BER by setting the length bytes of an encoding
769
+ * to zero and thus indicating that the following value will be
770
+ * sent in chunks. Infinite length encodings are always constructed.
771
+ * The end of such a stream of chunks is indicated by sending a
772
+ * EndOfContents value. SETs and SEQUENCEs may use an infinite length
773
+ * encoding, but also primitive types such as e.g. OCTET STRINGS or
774
+ * BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
775
+ */
776
+ static VALUE
777
+ krypt_asn1_data_set_inf_length(VALUE self, VALUE inf_length)
778
+ {
779
+ krypt_asn1_data *data;
780
+ krypt_asn1_header *header;
781
+ int new_inf;
782
+
783
+ int_asn1_data_get(self, data);
784
+
785
+ header = data->object->header;
786
+ new_inf = RTEST(inf_length) ? 1 : 0;
787
+ if (header->is_infinite == new_inf)
788
+ return inf_length;
789
+
790
+ header->is_infinite = new_inf;
791
+ int_invalidate_length(header);
792
+
793
+ int_asn1_data_set_modified(data, 1);
794
+ int_asn1_data_set_infinite_length(self, new_inf ? Qtrue : Qfalse);
795
+
796
+ return inf_length;
797
+ }
798
+
799
+ static int
800
+ int_asn1_data_value_decode(VALUE self, krypt_asn1_data *data, VALUE *out)
801
+ {
802
+ if (data->object->header->is_constructed) {
803
+ int result;
804
+ krypt_asn1_object *object = data->object;
805
+
806
+ result = int_asn1_cons_value_decode(self, data, out);
807
+ /* Invalidate the cached byte encoding */
808
+ xfree(object->bytes);
809
+ object->bytes = NULL;
810
+ object->bytes_len = 0;
811
+ return result;
812
+ } else {
813
+ return int_asn1_prim_value_decode(self, data, out);
814
+ }
815
+ }
816
+
817
+ static int
818
+ int_asn1_decode_value(VALUE self)
819
+ {
820
+ krypt_asn1_data *data;
821
+
822
+ int_asn1_data_get(self, data);
823
+ /* TODO: sync */
824
+ if (!int_asn1_data_is_decoded(data)) {
825
+ VALUE value;
826
+ if (int_asn1_data_value_decode(self, data, &value) == KRYPT_ERR) return KRYPT_ERR;
827
+ int_asn1_data_set_value(self, value);
828
+ int_asn1_data_set_decoded(data, 1);
829
+ }
830
+ return KRYPT_OK;
831
+ }
832
+
833
+ /*
834
+ * call-seq:
835
+ * asn1.value -> value
836
+ *
837
+ * Obtain the value of an ASN1Data.
838
+ * Please see Constructive and Primitive docs for the mappings between
839
+ * ASN.1 data types and Ruby classes.
840
+ */
841
+ static VALUE
842
+ krypt_asn1_data_get_value(VALUE self)
843
+ {
844
+ if (int_asn1_decode_value(self) == KRYPT_ERR)
845
+ krypt_error_raise(eKryptASN1Error, "Error while decoding value");
846
+ return int_asn1_data_get_value(self);
847
+ }
848
+
849
+ /*
850
+ * call-seq:
851
+ * asn1.value=(value) -> value
852
+ *
853
+ * Set the value of an ASN1Data.
854
+ * Please see Constructive and Primitive docs for the mappings between
855
+ * ASN.1 data types and Ruby classes.
856
+ */
857
+ static VALUE
858
+ krypt_asn1_data_set_value(VALUE self, VALUE value)
859
+ {
860
+ krypt_asn1_data *data;
861
+ krypt_asn1_object *object;
862
+ int is_constructed;
863
+
864
+ int_asn1_data_get(self, data);
865
+ int_asn1_data_set_value(self, value);
866
+
867
+ /* Free data that is now stale */
868
+ object = data->object;
869
+ int_invalidate_value(object);
870
+ is_constructed = rb_respond_to(value, sKrypt_ID_EACH);
871
+ if (object->header->is_constructed != is_constructed) {
872
+ object->header->is_constructed = is_constructed;
873
+ int_invalidate_tag(object->header);
874
+ data->codec = int_codec_for(data->object);
875
+ }
876
+
877
+ int_asn1_data_set_modified(data, 1);
878
+
879
+ return value;
880
+ }
881
+
882
+ static int
883
+ int_asn1_data_encode_to(VALUE self, binyo_outstream *out, VALUE value, krypt_asn1_data *data)
884
+ {
885
+ int ret;
886
+
887
+ if (data->object->header->is_constructed)
888
+ ret = int_asn1_cons_encode_to(self, out, value, data);
889
+ else
890
+ ret = int_asn1_prim_encode_to(self, out, value, data);
891
+ int_asn1_data_set_modified(data, 0); /* once encoded, modified status is reset */
892
+ return ret;
893
+ }
894
+
895
+ static int
896
+ int_asn1_make_explicit(VALUE value, int default_tag, VALUE *out)
897
+ {
898
+ VALUE universal;
899
+ VALUE klass;
900
+ VALUE ary;
901
+ krypt_asn1_data *data;
902
+
903
+ if (default_tag == -1) {
904
+ krypt_error_add("Cannot encode value with explicit tagging");
905
+ return KRYPT_ERR;
906
+ }
907
+
908
+ if (!krypt_asn1_infos[default_tag].klass) {
909
+ krypt_error_add("Unsupported tag: %d", default_tag);
910
+ return KRYPT_ERR;
911
+ }
912
+
913
+ ary = rb_ary_new();
914
+
915
+ klass = *(krypt_asn1_infos[default_tag].klass);
916
+ universal = rb_obj_alloc(klass);
917
+ universal = int_asn1_default_initialize(
918
+ universal,
919
+ value,
920
+ INT2NUM(default_tag),
921
+ default_tag,
922
+ ID2SYM(sKrypt_TC_UNIVERSAL)
923
+ );
924
+ int_asn1_data_get(universal, data);
925
+ int_handle_class_specifics(universal, data->object->header);
926
+ rb_ary_push(ary, universal);
927
+
928
+ *out = ary;
929
+ return KRYPT_OK;
930
+ }
931
+
932
+ static int
933
+ int_asn1_encode_to(binyo_outstream *out, krypt_asn1_data *data, VALUE self)
934
+ {
935
+ krypt_asn1_object *object = data->object;
936
+
937
+ /* TODO: sync */
938
+ if (!object->bytes) {
939
+ VALUE value;
940
+ value = int_asn1_data_get_value(self);
941
+ if (int_asn1_data_is_explicit(data)) {
942
+ if (int_asn1_make_explicit(value, data->default_tag, &value) == KRYPT_ERR) return KRYPT_ERR;
943
+ data->object->header->is_constructed = 1; /* explicitly tagged values are always constructed */
944
+ }
945
+ return int_asn1_data_encode_to(self, out, value, data);
946
+ }
947
+ else {
948
+ if (krypt_asn1_object_encode(out, object) == KRYPT_ERR)
949
+ return KRYPT_ERR;
950
+ return KRYPT_OK;
951
+ }
952
+ }
953
+
954
+ /*
955
+ * call-seq:
956
+ * asn1.encode_to(io) -> self
957
+ *
958
+ * * +io+: an IO-like object supporting IO#write
959
+ *
960
+ * Encodes this ASN1Data into a DER-encoded String value by writing the
961
+ * contents to an IO-like object.
962
+ * Newly created ASN1Data are DER-encoded except for the possibility of
963
+ * infinite length encodings. If a value with BER encoding was parsed and
964
+ * is not modified, the BER encoding will be preserved when encoding it
965
+ * again.
966
+ */
967
+ static VALUE
968
+ krypt_asn1_data_encode_to(VALUE self, VALUE io)
969
+ {
970
+ binyo_outstream *out;
971
+ krypt_asn1_data *data;
972
+ int result;
973
+
974
+ int_asn1_data_get(self, data);
975
+
976
+ out = binyo_outstream_new_value(io);
977
+ result = int_asn1_encode_to(out, data, self);
978
+ binyo_outstream_free(out);
979
+ if (result == KRYPT_ERR)
980
+ krypt_error_raise(eKryptASN1Error, "Error while encoding value");
981
+ return self;
982
+ }
983
+
984
+ static VALUE
985
+ int_asn1_data_to_der_cached(krypt_asn1_object *object)
986
+ {
987
+ binyo_outstream *out;
988
+ VALUE ret;
989
+ uint8_t *bytes;
990
+ size_t len;
991
+
992
+ len = object->header->tag_len + object->header->length_len + object->bytes_len;
993
+ bytes = ALLOCA_N(uint8_t, len);
994
+ out = binyo_outstream_new_bytes_prealloc(bytes, len);
995
+
996
+ if (krypt_asn1_object_encode(out, object) == KRYPT_ERR) {
997
+ binyo_outstream_free(out);
998
+ krypt_error_raise(eKryptASN1Error, "Error while encoding value");
999
+ }
1000
+
1001
+ ret = rb_str_new((const char *) bytes, len);
1002
+ binyo_outstream_free(out);
1003
+ return ret;
1004
+ }
1005
+
1006
+ static VALUE
1007
+ int_asn1_data_to_der_non_cached(krypt_asn1_data *data, VALUE self)
1008
+ {
1009
+ VALUE string;
1010
+ binyo_outstream *out;
1011
+ uint8_t *bytes;
1012
+ size_t len;
1013
+
1014
+ out = binyo_outstream_new_bytes_size(2048);
1015
+
1016
+ if (int_asn1_encode_to(out, data, self) == KRYPT_ERR) {
1017
+ binyo_outstream_free(out);
1018
+ krypt_error_raise(eKryptASN1Error, "Error while encoding value");
1019
+ }
1020
+
1021
+ len = binyo_outstream_bytes_get_bytes_free(out, &bytes);
1022
+ if (len > LONG_MAX)
1023
+ rb_raise(eKryptASN1Error, "Size of string too large: %ld", len);
1024
+ string = rb_str_new((const char *) bytes, (long) len);
1025
+ xfree(bytes);
1026
+ return string;
1027
+ }
1028
+
1029
+ /*
1030
+ * call-seq:
1031
+ * asn1.to_der -> DER-/BER-encoded String
1032
+ *
1033
+ * Encodes this ASN1Data into a DER-encoded String value. Newly created
1034
+ * ASN1Data are DER-encoded except for the possibility of infinite length
1035
+ * encodings. If a value with BER encoding was parsed and is not modified,
1036
+ * the BER encoding will be preserved when encoding it again.
1037
+ */
1038
+ static VALUE
1039
+ krypt_asn1_data_to_der(VALUE self)
1040
+ {
1041
+ krypt_asn1_data *data;
1042
+ krypt_asn1_object *object;
1043
+
1044
+ int_asn1_data_get(self, data);
1045
+ object = data->object;
1046
+
1047
+ if (object->bytes && object->header->tag_bytes && object->header->length_bytes)
1048
+ return int_asn1_data_to_der_cached(data->object);
1049
+ else
1050
+ return int_asn1_data_to_der_non_cached(data, self);
1051
+ }
1052
+
1053
+ /*
1054
+ * call-seq:
1055
+ * a <=> b -> -1 | 0 | +1
1056
+ *
1057
+ * ASN1Data includes the Comparable module.
1058
+ *
1059
+ * +<=>+ compares two instances of ASN1Data by comparing the bytes of their
1060
+ * encoding. The order applied is SET order, i.e. a < b iff tag of a < tag
1061
+ * of b. If tags are equal, SET OF order is applied, a lexicographical byte
1062
+ * order. Element order is decided based on the first byte where two elements
1063
+ * differ, the lower byte indicates the lower element.
1064
+ *
1065
+ * If two elements differ in length, but are equal up to the last byte of the
1066
+ * smaller element, the smaller element is the lower one.
1067
+ *
1068
+ * == Example
1069
+ *
1070
+ * Given the following SET of values
1071
+ *
1072
+ * [
1073
+ * Krypt::ASN1::OctetString.new("a"),
1074
+ * Krypt::ASN1::Null.new,
1075
+ * Krypt::ASN1::Boolean.new(true),
1076
+ * Krypt::ASN1::Integer.new(1)
1077
+ * ]
1078
+ *
1079
+ * the implied SET order is
1080
+ *
1081
+ * [
1082
+ * Krypt::ASN1::Boolean.new(true),
1083
+ * Krypt::ASN1::Integer.new(1)
1084
+ * Krypt::ASN1::OctetString.new("a"),
1085
+ * Krypt::ASN1::Null.new,
1086
+ * ]
1087
+ *
1088
+ * Given the following byte representations of OCTET STRINGS,
1089
+ *
1090
+ * [ "\x04\x06\aaabaa", "\x04\x01b", "\x04\x06aaabba", "\x04\x04aaab" ]
1091
+ *
1092
+ * the SET OF order implied is
1093
+ *
1094
+ * [ "\x04\x01b", "\x04\x04aaab", "\x04\x06aaabaa", "\x04\x06aaabba" ]
1095
+ */
1096
+ static VALUE
1097
+ krypt_asn1_data_cmp(VALUE a, VALUE b)
1098
+ {
1099
+ VALUE vs1, vs2;
1100
+ int result;
1101
+
1102
+ vs1 = krypt_asn1_data_to_der(a);
1103
+ if (!rb_respond_to(b, sKrypt_ID_TO_DER)) return Qnil;
1104
+ vs2 = krypt_to_der(b);
1105
+
1106
+ if(krypt_asn1_cmp_set_of((uint8_t *) RSTRING_PTR(vs1), (size_t) RSTRING_LEN(vs1),
1107
+ (uint8_t *) RSTRING_PTR(vs2), (size_t) RSTRING_LEN(vs2), &result) == KRYPT_ERR) {
1108
+ krypt_error_raise(eKryptASN1Error, "Error while comparing values");
1109
+ }
1110
+ return INT2NUM(result);
1111
+ }
1112
+ /* End ASN1Data methods */
1113
+
1114
+ /* ASN1Constructive methods */
1115
+
1116
+ static VALUE
1117
+ int_cons_each_i(VALUE cur, VALUE arg)
1118
+ {
1119
+ rb_yield(cur);
1120
+ return Qnil;
1121
+ }
1122
+
1123
+ /*
1124
+ * call-seq:
1125
+ * asn1_ary.each { |asn1| block } -> asn1_ary
1126
+ *
1127
+ * Calls <i>block</i> once for each element in +self+, passing that element
1128
+ * as parameter +asn1+. If no block is given, an enumerator is returned
1129
+ * instead.
1130
+ *
1131
+ * == Example
1132
+ * asn1_ary.each do |asn1|
1133
+ * pp asn1
1134
+ * end
1135
+ */
1136
+ static VALUE
1137
+ krypt_asn1_cons_each(VALUE self)
1138
+ {
1139
+ VALUE enumerable = krypt_asn1_data_get_value(self);
1140
+
1141
+ KRYPT_RETURN_ENUMERATOR(enumerable, sKrypt_ID_EACH);
1142
+
1143
+ if (rb_obj_is_kind_of(enumerable, rb_cArray))
1144
+ return rb_ary_each(krypt_asn1_data_get_value(self));
1145
+ else
1146
+ return rb_iterate(rb_each, enumerable, int_cons_each_i, Qnil);
1147
+ }
1148
+
1149
+ static int
1150
+ int_asn1_cons_value_decode(VALUE self, krypt_asn1_data *data, VALUE *out)
1151
+ {
1152
+ VALUE cur;
1153
+ binyo_instream *in;
1154
+ krypt_asn1_object *object;
1155
+ krypt_asn1_header *header;
1156
+ int ret;
1157
+
1158
+ *out = rb_ary_new();
1159
+ object = data->object;
1160
+ if (!object->bytes)
1161
+ return 1;
1162
+
1163
+ in = binyo_instream_new_bytes(object->bytes, object->bytes_len);
1164
+
1165
+ while ((ret = krypt_asn1_next_header(in, &header)) == KRYPT_OK) {
1166
+ if (!(cur = krypt_asn1_data_new(in, header))) {
1167
+ goto error;
1168
+ }
1169
+ rb_ary_push(*out, cur);
1170
+ }
1171
+
1172
+ if (ret == KRYPT_ERR) goto error;
1173
+
1174
+ /* discard EOC if available */
1175
+ if (object->header->is_infinite) {
1176
+ /* must be EOC because krypt_instream_chunked would otherwise indicate EOF */
1177
+ (void) rb_ary_pop(*out);
1178
+ }
1179
+
1180
+ binyo_instream_free(in);
1181
+ return KRYPT_OK;
1182
+
1183
+ error:
1184
+ binyo_instream_free(in);
1185
+ return KRYPT_ERR;
1186
+ }
1187
+
1188
+ static VALUE
1189
+ int_cons_encode_sub_elems_i(VALUE cur, VALUE args)
1190
+ {
1191
+ binyo_outstream *out = NULL;
1192
+ int *eoc_p;
1193
+ krypt_asn1_data *data;
1194
+ krypt_asn1_header *header;
1195
+
1196
+ Data_Get_Struct(rb_ary_entry(args, 0), binyo_outstream, out);
1197
+ Data_Get_Struct(rb_ary_entry(args, 1), int, eoc_p);
1198
+ int_asn1_data_get(cur, data);
1199
+
1200
+ if (int_asn1_encode_to(out, data, cur) == KRYPT_ERR)
1201
+ rb_raise(eKryptASN1Error, "Error while encoding values");
1202
+
1203
+ header = data->object->header;
1204
+ *eoc_p = header->tag == TAGS_END_OF_CONTENTS && header->tag_class == TAG_CLASS_UNIVERSAL;
1205
+
1206
+ return Qnil;
1207
+ }
1208
+
1209
+ static VALUE
1210
+ int_cons_encode_sub_elems_wrapped(VALUE args)
1211
+ {
1212
+ VALUE enumerable = rb_ary_pop(args);
1213
+
1214
+ rb_iterate(rb_each, enumerable, int_cons_encode_sub_elems_i, args);
1215
+
1216
+ return Qnil;
1217
+ }
1218
+
1219
+ static int
1220
+ int_cons_add_eoc(binyo_outstream *out)
1221
+ {
1222
+ krypt_asn1_data *data;
1223
+ VALUE eoc = int_asn1_end_of_contents_new_instance();
1224
+
1225
+ int_asn1_data_get(eoc, data);
1226
+ if (int_asn1_encode_to(out, data, eoc) == KRYPT_ERR) {
1227
+ krypt_error_add("Adding final END OF CONTENTS failed");
1228
+ return KRYPT_ERR;
1229
+ }
1230
+ return KRYPT_OK;
1231
+ }
1232
+
1233
+ static int
1234
+ int_cons_encode_sub_elems_enum(binyo_outstream *out, VALUE enumerable, int infinite)
1235
+ {
1236
+ VALUE args, wrapped_out, wrapped_eoc_p;
1237
+ int state = 0;
1238
+ int eoc_p = 0;
1239
+
1240
+ wrapped_out = Data_Wrap_Struct(rb_cObject, 0, 0, out);
1241
+ wrapped_eoc_p = Data_Wrap_Struct(rb_cObject, 0, 0, &eoc_p);
1242
+ args = rb_ary_new();
1243
+ rb_ary_push(args, wrapped_out);
1244
+ rb_ary_push(args, wrapped_eoc_p);
1245
+ rb_ary_push(args, enumerable);
1246
+ (void) rb_protect(int_cons_encode_sub_elems_wrapped, args, &state);
1247
+ if (state) return KRYPT_ERR;
1248
+ if (infinite && !eoc_p) { /* add EOC if it was missing */
1249
+ return int_cons_add_eoc(out);
1250
+ }
1251
+ return KRYPT_OK;
1252
+ }
1253
+
1254
+ static int
1255
+ int_cons_add_eoc_ary(binyo_outstream *out, VALUE ary, long i)
1256
+ {
1257
+ krypt_asn1_data *data;
1258
+ krypt_asn1_header *header;
1259
+ VALUE last = rb_ary_entry(ary, i - 1);
1260
+
1261
+ int_asn1_data_get(last, data);
1262
+ header = data->object->header;
1263
+ if (header->tag != TAGS_END_OF_CONTENTS || header->tag_class != TAG_CLASS_UNIVERSAL) {
1264
+ return int_cons_add_eoc(out);
1265
+ }
1266
+ return KRYPT_OK;
1267
+ }
1268
+
1269
+ static int
1270
+ int_cons_encode_sub_elems_ary(binyo_outstream *out, VALUE ary, int infinite)
1271
+ {
1272
+ long size, i;
1273
+ VALUE cur;
1274
+ size = RARRAY_LEN(ary);
1275
+
1276
+ for (i=0; i < size; i++) {
1277
+ krypt_asn1_data *data;
1278
+
1279
+ cur = rb_ary_entry(ary, i);
1280
+ int_asn1_data_get(cur, data);
1281
+ if (int_asn1_encode_to(out, data, cur) == KRYPT_ERR) return KRYPT_ERR;
1282
+ }
1283
+
1284
+ if (infinite) { /* add closing EOC if it was missing */
1285
+ if (int_cons_add_eoc_ary(out, ary, i) == KRYPT_ERR) return KRYPT_ERR;
1286
+ }
1287
+ return KRYPT_OK;
1288
+ }
1289
+
1290
+ static VALUE
1291
+ int_cons_sort_to_ary(VALUE cur, VALUE ary)
1292
+ {
1293
+ rb_ary_push(ary, cur);
1294
+ return Qnil;
1295
+ }
1296
+
1297
+ static VALUE
1298
+ int_cons_sort_set(VALUE enumerable)
1299
+ {
1300
+ VALUE tmp_ary;
1301
+
1302
+ if (rb_respond_to(enumerable, sKrypt_ID_SORT_BANG)) {
1303
+ (void) rb_funcall(enumerable, sKrypt_ID_SORT_BANG, 0);
1304
+ return enumerable;
1305
+ }
1306
+ if (rb_respond_to(enumerable, sKrypt_ID_SORT)) {
1307
+ VALUE copy = rb_funcall(enumerable, sKrypt_ID_SORT, 0);
1308
+ return copy;
1309
+ }
1310
+
1311
+ tmp_ary = rb_ary_new();
1312
+ (void) rb_iterate(rb_each, enumerable, int_cons_sort_to_ary, tmp_ary);
1313
+ (void) rb_funcall(tmp_ary, sKrypt_ID_SORT_BANG, 0);
1314
+ return tmp_ary;
1315
+ }
1316
+
1317
+ static int
1318
+ int_cons_encode_sub_elems(binyo_outstream *out, VALUE enumerable, krypt_asn1_data *data)
1319
+ {
1320
+ krypt_asn1_header *header;
1321
+
1322
+ if (NIL_P(enumerable))
1323
+ return KRYPT_OK;
1324
+
1325
+ header = data->object->header;
1326
+ if (header->tag == TAGS_SET &&
1327
+ header->tag_class == TAG_CLASS_UNIVERSAL &&
1328
+ int_asn1_data_is_modified(data))
1329
+ {
1330
+ /* We need to apply proper SET (OF) encoding when creating a new SET */
1331
+ enumerable = int_cons_sort_set(enumerable);
1332
+ }
1333
+
1334
+ /* Optimize for Array */
1335
+ if (TYPE(enumerable) == T_ARRAY)
1336
+ return int_cons_encode_sub_elems_ary(out, enumerable, header->is_infinite);
1337
+ else
1338
+ return int_cons_encode_sub_elems_enum(out, enumerable, header->is_infinite);
1339
+ }
1340
+
1341
+ static int
1342
+ int_asn1_cons_update_length(VALUE ary, krypt_asn1_data *data, uint8_t **out, size_t *outlen)
1343
+ {
1344
+ binyo_outstream *bos = binyo_outstream_new_bytes_size(1024);
1345
+
1346
+ if (int_cons_encode_sub_elems(bos, ary, data) == KRYPT_ERR) {
1347
+ binyo_outstream_free(bos);
1348
+ return KRYPT_ERR;
1349
+ }
1350
+ *outlen = binyo_outstream_bytes_get_bytes_free(bos, out);
1351
+ return KRYPT_OK;
1352
+ }
1353
+
1354
+ static int
1355
+ int_asn1_cons_encode_update(binyo_outstream *out, VALUE ary, krypt_asn1_data *data)
1356
+ {
1357
+ size_t len;
1358
+ uint8_t *bytes = NULL;
1359
+ krypt_asn1_header *header = data->object->header;
1360
+
1361
+ if (int_asn1_cons_update_length(ary, data, &bytes, &len) == KRYPT_ERR) goto error;
1362
+ header->length = len;
1363
+ if (krypt_asn1_header_encode(out, header) == KRYPT_ERR) goto error;
1364
+ if (header->length > 0) {
1365
+ if (binyo_outstream_write(out, bytes, len) == BINYO_ERR) goto error;
1366
+ }
1367
+
1368
+ xfree(bytes);
1369
+ return KRYPT_OK;
1370
+ error:
1371
+ if (bytes) xfree(bytes);
1372
+ return KRYPT_ERR;
1373
+ }
1374
+
1375
+
1376
+ static int
1377
+ int_asn1_cons_encode_to(VALUE self, binyo_outstream *out, VALUE ary, krypt_asn1_data *data)
1378
+ {
1379
+ krypt_asn1_header *header;
1380
+
1381
+ header = data->object->header;
1382
+
1383
+ if (header->tag_class == TAG_CLASS_UNIVERSAL) {
1384
+ int tag = header->tag;
1385
+ if (tag != TAGS_SEQUENCE && tag != TAGS_SET && !header->is_infinite) {
1386
+ krypt_error_add("Primitive constructed values must be infinite length");
1387
+ return KRYPT_ERR;
1388
+ }
1389
+ }
1390
+
1391
+ /* If the length encoding is still cached or we have an infinite length
1392
+ * value, we don't need to compute the length first, we can simply start
1393
+ * encoding */
1394
+ if (header->length_bytes == NULL && !header->is_infinite) {
1395
+ return int_asn1_cons_encode_update(out, ary, data);
1396
+ } else {
1397
+ if (krypt_asn1_header_encode(out, header) == KRYPT_ERR) return KRYPT_ERR;
1398
+ if (int_cons_encode_sub_elems(out, ary, data) == KRYPT_ERR) return KRYPT_ERR;
1399
+ return KRYPT_OK;
1400
+ }
1401
+ }
1402
+
1403
+ /* End ASN1Constructive methods */
1404
+
1405
+ /* ASN1Primitive methods */
1406
+
1407
+ static int
1408
+ int_asn1_prim_value_decode(VALUE self, krypt_asn1_data *data, VALUE *out)
1409
+ {
1410
+ krypt_asn1_object *object;
1411
+
1412
+ object = data->object;
1413
+ return data->codec->decoder(self, object->bytes, object->bytes_len, out);
1414
+ }
1415
+
1416
+ static int
1417
+ int_asn1_prim_encode_to(VALUE self, binyo_outstream *out, VALUE value, krypt_asn1_data *data)
1418
+ {
1419
+ krypt_asn1_object *object;
1420
+
1421
+ object = data->object;
1422
+
1423
+ if (object->header->tag_class == TAG_CLASS_UNIVERSAL) {
1424
+ int tag = object->header->tag;
1425
+ if (tag == TAGS_SEQUENCE || tag == TAGS_SET) {
1426
+ krypt_error_add("Set/Sequence value must be constructed");
1427
+ return KRYPT_ERR;
1428
+ }
1429
+ }
1430
+
1431
+ if (data->codec->validator(self, value) == KRYPT_ERR) return KRYPT_ERR;
1432
+ if (data->codec->encoder(self, value, &object->bytes, &object->bytes_len) == KRYPT_ERR) return KRYPT_ERR;
1433
+ object->header->length = object->bytes_len;
1434
+ if (krypt_asn1_object_encode(out, object) == KRYPT_ERR) return KRYPT_ERR;
1435
+
1436
+ return KRYPT_OK;
1437
+ }
1438
+
1439
+ static VALUE
1440
+ krypt_asn1_bit_string_set_unused_bits(VALUE self, VALUE unused_bits)
1441
+ {
1442
+ rb_ivar_set(self, sKrypt_IV_UNUSED_BITS, unused_bits);
1443
+ return unused_bits;
1444
+ }
1445
+
1446
+ /**
1447
+ * If a bit string was parsed, we first need to parse
1448
+ * the internal value before we can give the precise
1449
+ * value of unused_bits.
1450
+ */
1451
+ static VALUE
1452
+ krypt_asn1_bit_string_get_unused_bits(VALUE self)
1453
+ {
1454
+ if (int_asn1_decode_value(self) == KRYPT_ERR)
1455
+ krypt_error_raise(eKryptASN1Error, "Error while decoding value");
1456
+ return rb_ivar_get(self, sKrypt_IV_UNUSED_BITS);
1457
+ }
1458
+
1459
+ /* End ASN1Primitive methods */
1460
+
1461
+ int
1462
+ krypt_asn1_decode_stream(binyo_instream *in, VALUE *out)
1463
+ {
1464
+ krypt_asn1_header *header;
1465
+ VALUE ret;
1466
+ int result;
1467
+
1468
+ result = krypt_asn1_next_header(in, &header);
1469
+ if (result == KRYPT_ASN1_EOF || result == KRYPT_ERR) return result;
1470
+
1471
+ ret = krypt_asn1_data_new(in, header);
1472
+ if (NIL_P(ret)) {
1473
+ krypt_asn1_header_free(header);
1474
+ return KRYPT_ERR;
1475
+ }
1476
+ *out = ret;
1477
+ return KRYPT_OK;
1478
+ }
1479
+
1480
+ static VALUE
1481
+ int_asn1_fallback_decode(binyo_instream *in, binyo_instream *cache)
1482
+ {
1483
+ VALUE ret;
1484
+ uint8_t *lookahead = NULL;
1485
+ size_t la_size;
1486
+ binyo_instream *bytes;
1487
+ binyo_instream *retry;
1488
+ int result;
1489
+
1490
+ la_size = binyo_instream_cache_get_bytes(cache, &lookahead);
1491
+ binyo_instream_cache_free_wrapper(cache); /* do not use krypt_instream_free, would free in too */
1492
+ bytes = binyo_instream_new_bytes(lookahead, la_size);
1493
+ retry = binyo_instream_new_seq(bytes, in); /*chain cached bytes and original stream */
1494
+ result = krypt_asn1_decode_stream(retry, &ret);
1495
+ if (lookahead)
1496
+ xfree(lookahead);
1497
+ binyo_instream_free(retry);
1498
+ if (result != KRYPT_OK)
1499
+ krypt_error_raise(eKryptASN1Error, "Error while DER-decoding value");
1500
+ return ret;
1501
+ }
1502
+
1503
+ /**
1504
+ * call-seq:
1505
+ * ASN1.decode(src) -> ASN1Data
1506
+ *
1507
+ * * +src+: May either be a +String+ containing a DER-/PEM-encoded value, an
1508
+ * IO-like object supporting IO#read and IO#seek or any arbitrary
1509
+ * object that supports either a +to_der+ or a +to_pem+ method
1510
+ * transforming it into a DER-/BER-encoded or PEM-encoded +String+.
1511
+ *
1512
+ * Decodes arbitrary DER- or PEM-encoded ASN.1 objects and returns an instance
1513
+ * (or a subclass) of ASN1Data.
1514
+ *
1515
+ * == Examples
1516
+ * io = File.open("my.der", "rb")
1517
+ * asn1 = Krypt::ASN1.decode(io)
1518
+ * io.close
1519
+ *
1520
+ * str = #some PEM-encoded string
1521
+ * asn1 = Krypt::ASN1.decode(str)
1522
+ *
1523
+ * tagged = Krypt::ASN1::Integer.new(1, 0, :CONTEXT_SPECIFIC)
1524
+ * tagged.tag = Krypt::ASN1::INTEGER
1525
+ * tagged.tag_class = :UNIVERSAL
1526
+ * int = Krypt::ASN1.decode(tagged)
1527
+ * puts int.tag # => 2
1528
+ * puts int.tag_class # => :UNIVERSAL
1529
+ * puts int.value # => 1
1530
+ */
1531
+ static VALUE
1532
+ krypt_asn1_decode(VALUE self, VALUE obj)
1533
+ {
1534
+ binyo_instream *in;
1535
+ binyo_instream *cache;
1536
+ binyo_instream *pem;
1537
+ VALUE ret;
1538
+
1539
+ /* Try PEM first, if it fails, try as DER */
1540
+ in = krypt_instream_new_value_der(obj);
1541
+ cache = binyo_instream_new_cache(in);
1542
+ pem = krypt_instream_new_pem(cache);
1543
+ if (krypt_asn1_decode_stream(pem, &ret) != KRYPT_OK) {
1544
+ krypt_instream_pem_free_wrapper(pem);
1545
+ return int_asn1_fallback_decode(in, cache);
1546
+ }
1547
+ binyo_instream_free(pem); /* also frees in */
1548
+ return ret;
1549
+ }
1550
+
1551
+ /**
1552
+ * call-seq:
1553
+ * ASN1.decode_der(der) -> ASN1Data
1554
+ *
1555
+ * * +der+: May either be a +String+ containing a DER-encoded value, an
1556
+ * IO-like object supporting IO#read and IO#seek or any arbitrary
1557
+ * object that supports a +to_der+ method transforming it into a
1558
+ * DER-/BER-encoded +String+.
1559
+ *
1560
+ * Decodes a DER-encoded ASN.1 object and returns an instance (or a subclass)
1561
+ * of ASN1Data. Can be used in the same way as +ASN1Data#decode+, except that
1562
+ * +decode_der+ explicitly assumes a DER-encoded source.
1563
+ */
1564
+ static VALUE
1565
+ krypt_asn1_decode_der(VALUE self, VALUE obj)
1566
+ {
1567
+ VALUE ret;
1568
+ int result;
1569
+
1570
+ binyo_instream *in = krypt_instream_new_value_der(obj);
1571
+ result = krypt_asn1_decode_stream(in, &ret);
1572
+ binyo_instream_free(in);
1573
+ if (result != KRYPT_OK)
1574
+ krypt_error_raise(eKryptASN1Error, "Error while DER-decoding value");
1575
+ return ret;
1576
+ }
1577
+
1578
+ /**
1579
+ * call-seq:
1580
+ * ASN1.decode_pem(pem) -> ASN1Data
1581
+ *
1582
+ * * +pem+: May either be a +String+ containing a PEM-encoded value, an
1583
+ * IO-like object supporting IO#read and IO#seek or any arbitrary
1584
+ * object that supports a +to_pem+ method transforming it into a
1585
+ * PEM-encoded +String+.
1586
+ *
1587
+ * Decodes a PEM-encoded ASN.1 object and returns an instance (or a subclass)
1588
+ * of ASN1Data. Can be used in the same way as +ASN1Data#decode+, except that
1589
+ * +decode_pem+ explicitly assumes a PEM-encoded source.
1590
+ */
1591
+ static VALUE
1592
+ krypt_asn1_decode_pem(VALUE self, VALUE obj)
1593
+ {
1594
+ VALUE ret;
1595
+ int result;
1596
+
1597
+ binyo_instream *pem;
1598
+ pem = krypt_instream_new_pem(krypt_instream_new_value_pem(obj));
1599
+ result = krypt_asn1_decode_stream(pem, &ret);
1600
+ binyo_instream_free(pem);
1601
+ if (result != KRYPT_OK)
1602
+ krypt_error_raise(eKryptASN1Error, "Error while PEM-decoding value");
1603
+ return ret;
1604
+ }
1605
+
1606
+ /**
1607
+ * Returns an ID representing the Symbol that stands for the corresponding
1608
+ * tag class.
1609
+ *
1610
+ * @param tag_class The raw tag class value
1611
+ * @return A Ruby Symbol representing the tag class, e.g.
1612
+ * :UNIVERSAL, or 0 if the class is not recognized
1613
+ */
1614
+ ID
1615
+ krypt_asn1_tag_class_for_int(int tag_class)
1616
+ {
1617
+ switch (tag_class) {
1618
+ case TAG_CLASS_UNIVERSAL:
1619
+ return sKrypt_TC_UNIVERSAL;
1620
+ case TAG_CLASS_APPLICATION:
1621
+ return sKrypt_TC_APPLICATION;
1622
+ case TAG_CLASS_CONTEXT_SPECIFIC:
1623
+ return sKrypt_TC_CONTEXT_SPECIFIC;
1624
+ case TAG_CLASS_PRIVATE:
1625
+ return sKrypt_TC_PRIVATE;
1626
+ default:
1627
+ krypt_error_add("Unknown tag class: %d", tag_class);
1628
+ return 0;
1629
+ }
1630
+ }
1631
+
1632
+ /**
1633
+ * Returns an integer representing the tag class of the corresponding
1634
+ * symbol.
1635
+ *
1636
+ * @param tag_class The tag class ID
1637
+ * @return A positive integer representing the tag class
1638
+ * or 0 if the ID was not recognized
1639
+ */
1640
+ int
1641
+ krypt_asn1_tag_class_for_id(ID tag_class)
1642
+ {
1643
+ VALUE str;
1644
+ if (tag_class == sKrypt_TC_UNIVERSAL)
1645
+ return TAG_CLASS_UNIVERSAL;
1646
+ else if (tag_class == sKrypt_TC_CONTEXT_SPECIFIC)
1647
+ return TAG_CLASS_CONTEXT_SPECIFIC;
1648
+ else if (tag_class == sKrypt_TC_EXPLICIT)
1649
+ return TAG_CLASS_CONTEXT_SPECIFIC;
1650
+ else if (tag_class == sKrypt_TC_IMPLICIT)
1651
+ return TAG_CLASS_CONTEXT_SPECIFIC;
1652
+ else if (tag_class == sKrypt_TC_APPLICATION)
1653
+ return TAG_CLASS_APPLICATION;
1654
+ else if (tag_class == sKrypt_TC_PRIVATE)
1655
+ return TAG_CLASS_PRIVATE;
1656
+ str = rb_funcall(ID2SYM(tag_class), rb_intern("to_s"), 0);
1657
+ StringValueCStr(str);
1658
+ krypt_error_add("Unknown tag class: %s", RSTRING_PTR(str));
1659
+ return KRYPT_ERR;
1660
+ }
1661
+
1662
+ void
1663
+ Init_krypt_asn1(void)
1664
+ {
1665
+ #if 0
1666
+ mKrypt = rb_define_module("Krypt"); /* Let RDoc know */
1667
+ #endif
1668
+
1669
+ VALUE ary;
1670
+ int i;
1671
+
1672
+ sKrypt_TC_UNIVERSAL = rb_intern("UNIVERSAL");
1673
+ sKrypt_TC_APPLICATION = rb_intern("APPLICATION");
1674
+ sKrypt_TC_CONTEXT_SPECIFIC = rb_intern("CONTEXT_SPECIFIC");
1675
+ sKrypt_TC_PRIVATE = rb_intern("PRIVATE");
1676
+ sKrypt_TC_EXPLICIT = rb_intern("EXPLICIT");
1677
+ sKrypt_TC_IMPLICIT = rb_intern("IMPLICIT");
1678
+
1679
+ sKrypt_IV_TAG = rb_intern("@tag");
1680
+ sKrypt_IV_TAG_CLASS = rb_intern("@tag_class");
1681
+ sKrypt_IV_INF_LEN = rb_intern("@infinite_length");
1682
+ sKrypt_IV_UNUSED_BITS = rb_intern("@unused_bits");
1683
+
1684
+ sKrypt_IV_VALUE = rb_intern("@value");
1685
+
1686
+ /*
1687
+ * Document-module: Krypt::ASN1
1688
+ *
1689
+ * Abstract Syntax Notation One (or ASN.1) is a notation syntax to
1690
+ * describe data structures and is defined in ITU-T X.680. ASN.1 itself
1691
+ * does not mandate any encoding or parsing rules, but usually ASN.1 data
1692
+ * structures are encoded using the Distinguished Encoding Rules (DER) or
1693
+ * less often the Basic Encoding Rules (BER) described in ITU-T X.690. DER
1694
+ * and BER encodings are binary Tag-Length-Value (TLV) encodings that are
1695
+ * quite concise compared to other popular data description formats such
1696
+ * as XML, JSON etc.
1697
+ * ASN.1 data structures are very common in cryptographic applications,
1698
+ * e.g. X.509 public key certificates or certificate revocation lists
1699
+ * (CRLs) are all defined in ASN.1 and DER-encoded. ASN.1, DER and BER are
1700
+ * the building blocks of applied cryptography.
1701
+ * The ASN1 module provides the necessary classes that allow generation
1702
+ * of ASN.1 data structures and the methods to encode them using a DER
1703
+ * encoding. The decode method allows parsing arbitrary BER-/DER-encoded
1704
+ * data to a Ruby object that can then be modified and re-encoded at will.
1705
+ *
1706
+ * BER encodings of a parsed value are preserved when re-encoding them in
1707
+ * order to avoid breaking digital signatures that were computed over these
1708
+ * encodings. Once a parsed value is replaced by another manually,
1709
+ * the new value will be encoded in DER format, regardless of the previous
1710
+ * encoding of the old value.
1711
+ *
1712
+ * == ASN.1 class hierarchy
1713
+ *
1714
+ * The base class representing ASN.1 structures is ASN1Data. ASN1Data offers
1715
+ * attributes to read and set the +tag+, the +tag_class+ and finally the
1716
+ * +value+ of a particular ASN.1 item. Upon parsing, any tagged values
1717
+ * (implicit or explicit) will be represented by ASN1Data instances because
1718
+ * their "real type" can only be determined using out-of-band information
1719
+ * from the ASN.1 type declaration.
1720
+ *
1721
+ * === Constructive
1722
+ *
1723
+ * Constructive is, as its name implies, the base class for all
1724
+ * constructed encodings, i.e. those that consist of several values,
1725
+ * opposed to "primitive" encodings with just one single value.
1726
+ * Primitive values that are encoded with "infinite length" are typically
1727
+ * constructed (their values come in multiple chunks) and are therefore
1728
+ * represented by instances of Constructive. The value of a parsed
1729
+ * Constructive is always an Array.
1730
+ *
1731
+ * ==== ASN1::Set and ASN1::Sequence
1732
+ *
1733
+ * The most common constructive encodings are SETs and SEQUENCEs, which is
1734
+ * why there are two sub-classes of Constructive representing each of
1735
+ * them.
1736
+ *
1737
+ * === Primitive
1738
+ *
1739
+ * This is the super class of all primitive values. Primitive
1740
+ * itself is not used when parsing ASN.1 data, all values are either
1741
+ * instances of a corresponding sub-class of Primitive or they are
1742
+ * instances of ASN1Data if the value was tagged implicitly or explicitly.
1743
+ * Please cf. Primitive documentation for details on sub-classes and
1744
+ * their respective mappings of ASN.1 data types to Ruby objects.
1745
+ *
1746
+ * == Possible values for +tag_class+
1747
+ *
1748
+ * It is possible to create arbitrary ASN1Data objects that also support
1749
+ * a PRIVATE or APPLICATION tag class. Possible values for the +tag_class+
1750
+ * attribute are:
1751
+ * * +:UNIVERSAL+ (the default for untagged values)
1752
+ * * +:CONTEXT_SPECIFIC+ (the default for tagged values)
1753
+ * * +:APPLICATION+
1754
+ * * +:PRIVATE+
1755
+ *
1756
+ * Additionally the following two may be used:
1757
+ * * +:IMPLICIT+
1758
+ * * +:EXPLICIT+
1759
+ *
1760
+ * where +:IMPLICIT+ is simply a synonym for +:CONTEXT_SPECIFIC+, and
1761
+ * exists mostly for convenience reasons to match real ASN.1 definitions
1762
+ * more closely. +:EXPLICIT+ on the other hand can be thought of as a
1763
+ * hint for encoding an ASN1Data from scratch. Neither +:IMPLICIT+ nor
1764
+ * +:EXPLICIT+ will ever be assigned during parsing. Both translate to
1765
+ * +:CONTEXT_SPECIFIC+ eventually when being encoded. The difference is
1766
+ * that +:EXPLICIT+ will force the corresponding value to be encoded
1767
+ * with explicit tagging, whereas +:IMPLICIT+, you guessed right, enforces
1768
+ * implicit tagging, in the same way that +:CONTEXT_SPECIFIC+ does.
1769
+ *
1770
+ * == Tag constants
1771
+ *
1772
+ * There is a constant defined for each universal tag:
1773
+ * * Krypt::ASN1::EOC (0)
1774
+ * * Krypt::ASN1::BOOLEAN (1)
1775
+ * * Krypt::ASN1::INTEGER (2)
1776
+ * * Krypt::ASN1::BIT_STRING (3)
1777
+ * * Krypt::ASN1::OCTET_STRING (4)
1778
+ * * Krypt::ASN1::NULL (5)
1779
+ * * Krypt::ASN1::OBJECT (6)
1780
+ * * Krypt::ASN1::ENUMERATED (10)
1781
+ * * Krypt::ASN1::UTF8STRING (12)
1782
+ * * Krypt::ASN1::SEQUENCE (16)
1783
+ * * Krypt::ASN1::SET (17)
1784
+ * * Krypt::ASN1::NUMERICSTRING (18)
1785
+ * * Krypt::ASN1::PRINTABLESTRING (19)
1786
+ * * Krypt::ASN1::T61STRING (20)
1787
+ * * Krypt::ASN1::VIDEOTEXSTRING (21)
1788
+ * * Krypt::ASN1::IA5STRING (22)
1789
+ * * Krypt::ASN1::UTCTIME (23)
1790
+ * * Krypt::ASN1::GENERALIZEDTIME (24)
1791
+ * * Krypt::ASN1::GRAPHICSTRING (25)
1792
+ * * Krypt::ASN1::ISO64STRING (26)
1793
+ * * Krypt::ASN1::GENERALSTRING (27)
1794
+ * * Krypt::ASN1::UNIVERSALSTRING (28)
1795
+ * * Krypt::ASN1::BMPSTRING (30)
1796
+ *
1797
+ * == UNIVERSAL_TAG_NAME constant
1798
+ *
1799
+ * An Array that stores the name of a given tag number. These names are
1800
+ * the same as the name of the tag constant that is additionally defined,
1801
+ * e.g. UNIVERSAL_TAG_NAME[2] = "INTEGER" and Krypt::ASN1::INTEGER = 2.
1802
+ *
1803
+ * == Example usage
1804
+ *
1805
+ * === Decoding and viewing a DER-encoded file
1806
+ * require 'krypt'
1807
+ * require 'pp'
1808
+ * File.open('data.der', 'rb') do |f|
1809
+ * pp Krypt::ASN1.decode(f)
1810
+ * end
1811
+ *
1812
+ * === Creating an ASN.1 structure and DER-encoding it
1813
+ * require 'krypt'
1814
+ * version = Krypt::ASN1::Integer.new(1)
1815
+ * # 0-tagged with context-specific tag class
1816
+ * serial = Krypt::ASN1::Integer.new(12345, 0, :CONTEXT_SPECIFIC)
1817
+ * name = Krypt::ASN1::PrintableString.new('Data 1')
1818
+ * sequence = Krypt::ASN1::Sequence.new( [ version, serial, name ] )
1819
+ * der = sequence.to_der
1820
+ */
1821
+ mKryptASN1 = rb_define_module_under(mKrypt, "ASN1");
1822
+
1823
+ /* Document-class: Krypt::ASN1::ASN1Error
1824
+ *
1825
+ * Generic error class for all errors raised in ASN1 and any of the
1826
+ * classes defined under it.
1827
+ */
1828
+ eKryptASN1Error = rb_define_class_under(mKryptASN1, "ASN1Error", eKryptError);
1829
+
1830
+ /* Document-class: Krypt::ASN1::ParseError
1831
+ *
1832
+ * Generic error class for all errors raised while parsing from a stream
1833
+ * with Krypt::ASN1::Parser or Krypt::ASN1::Header.
1834
+ */
1835
+ eKryptASN1ParseError = rb_define_class_under(mKryptASN1, "ParseError", eKryptASN1Error);
1836
+
1837
+ /* Document-class: Krypt::ASN1::SerializeError
1838
+ *
1839
+ * Generic error class for all errors raised while writing to a stream
1840
+ * with Krypt::ASN1::Header#encode_to.
1841
+ */
1842
+ eKryptASN1SerializeError = rb_define_class_under(mKryptASN1, "SerializeError", eKryptASN1Error);
1843
+
1844
+ ary = rb_ary_new();
1845
+ /*
1846
+ * Array storing tag names at the tag's index.
1847
+ */
1848
+ rb_define_const(mKryptASN1, "UNIVERSAL_TAG_NAME", ary);
1849
+ for(i = 0; i < krypt_asn1_infos_size; i++){
1850
+ if(krypt_asn1_infos[i].name[0] == '[') continue;
1851
+ rb_define_const(mKryptASN1, krypt_asn1_infos[i].name, INT2NUM(i));
1852
+ rb_ary_store(ary, i, rb_str_new2(krypt_asn1_infos[i].name));
1853
+ }
1854
+
1855
+ rb_define_module_function(mKryptASN1, "decode", krypt_asn1_decode, 1);
1856
+ rb_define_module_function(mKryptASN1, "decode_der", krypt_asn1_decode_der, 1);
1857
+ rb_define_module_function(mKryptASN1, "decode_pem", krypt_asn1_decode_pem, 1);
1858
+
1859
+ /* Document-class: Krypt::ASN1::ASN1Data
1860
+ *
1861
+ * The top-level class representing any ASN.1 object. When parsed by
1862
+ * ASN1.decode, tagged values are always represented by an instance
1863
+ * of ASN1Data.
1864
+ *
1865
+ * == The role of ASN1Data for parsing tagged values
1866
+ *
1867
+ * When encoding an ASN.1 type it is inherently clear what original
1868
+ * type (e.g. INTEGER, OCTET STRING etc.) this value has, regardless
1869
+ * of its tagging.
1870
+ * But opposed to the time an ASN.1 type is to be encoded, when parsing
1871
+ * them it is not possible to deduce the "real type" of tagged
1872
+ * values. This is why tagged values are generally parsed into ASN1Data
1873
+ * instances, but with a different outcome for implicit and explicit
1874
+ * tagging.
1875
+ *
1876
+ * === Example of a parsed implicitly tagged value
1877
+ *
1878
+ * An implicitly 1-tagged INTEGER value will be parsed as an
1879
+ * ASN1Data with
1880
+ * * +tag+ equal to 1
1881
+ * * +tag_class+ equal to +:CONTEXT_SPECIFIC+
1882
+ * * +value+ equal to a +String+ that carries the raw encoding
1883
+ * of the INTEGER.
1884
+ * This implies that a subsequent decoding step is required to
1885
+ * completely decode implicitly tagged values.
1886
+ *
1887
+ * === Example of a parsed explicitly tagged value
1888
+ *
1889
+ * An explicitly 1-tagged INTEGER value will be parsed as an
1890
+ * ASN1Data with
1891
+ * * +tag+ equal to 1
1892
+ * * +tag_class+ equal to +:CONTEXT_SPECIFIC+
1893
+ * * +value+ equal to an +Array+ with one single element, an
1894
+ * instance of Krypt::ASN1::Integer, i.e. the inner element
1895
+ * is the non-tagged primitive value, and the tagging is represented
1896
+ * in the outer ASN1Data
1897
+ *
1898
+ * == Example - Decoding an implicitly tagged INTEGER
1899
+ * int = Krypt::ASN1::Integer.new(1, 0, :CONTEXT_SPECIFIC) # implicit 0-tagged
1900
+ * seq = Krypt::ASN1::Sequence.new( [int] )
1901
+ * der = seq.to_der
1902
+ * asn1 = Krypt::ASN1.decode(der)
1903
+ * # pp asn1 => #<Krypt::ASN1::Sequence:0x87326e0
1904
+ * # @infinite_length=false,
1905
+ * # @tag=16,
1906
+ * # @tag_class=:UNIVERSAL>
1907
+ * # pp asn1.value => [#<Krypt::ASN1::ASN1Data:0x87326f4
1908
+ * # @infinite_length=false,
1909
+ * # @tag=0,
1910
+ * # @tag_class=:CONTEXT_SPECIFIC>]
1911
+ * # pp asn1.value[0].value => "\x01"
1912
+ * raw_int = asn1.value[0]
1913
+ * # manually rewrite tag and tag class to make it an UNIVERSAL value
1914
+ * raw_int.tag = OpenSSL::ASN1::INTEGER
1915
+ * raw_int.tag_class = :UNIVERSAL
1916
+ * int2 = Krypt::ASN1.decode(raw_int)
1917
+ * puts int2.value # => 1
1918
+ *
1919
+ * == Example - Decoding an explicitly tagged INTEGER
1920
+ * int = Krypt::ASN1::Integer.new(1)
1921
+ * data = Krypt::ASN1Data.new([int], 0, :CONTEXT_SPECIFIC) # explicit 0-tagged
1922
+ * seq = Krypt::ASN1::Sequence.new( [data] )
1923
+ * der = seq.to_der
1924
+ * asn1 = Krypt::ASN1.decode(der)
1925
+ * # pp asn1 => #<Krypt::ASN1::Sequence:0x87326e0
1926
+ * # @infinite_length=false,
1927
+ * # @tag=16,
1928
+ * # @tag_class=:UNIVERSAL>
1929
+ * # pp asn1.value => [#<Krypt::ASN1::ASN1Data:0x87326f4
1930
+ * # @infinite_length=false,
1931
+ * # @tag=0,
1932
+ * # @tag_class=:CONTEXT_SPECIFIC>]
1933
+ * # pp asn1.value[0].value => [#<Krypt::ASN1::Integer:0x85bf308
1934
+ * # @infinite_length=false,
1935
+ * # @tag=2,
1936
+ * # @tag_class=:UNIVERSAL>]
1937
+ * int2 = asn1.value[0].value[0]
1938
+ * puts int2.value # => 1
1939
+ */
1940
+ cKryptASN1Data = rb_define_class_under(mKryptASN1, "ASN1Data", rb_cObject);
1941
+ rb_include_module(cKryptASN1Data, rb_mComparable);
1942
+ rb_define_alloc_func(cKryptASN1Data, krypt_asn1_data_alloc);
1943
+ rb_define_method(cKryptASN1Data, "initialize", krypt_asn1_data_initialize, 3);
1944
+ rb_define_method(cKryptASN1Data, "tag", krypt_asn1_data_get_tag, 0);
1945
+ rb_define_method(cKryptASN1Data, "tag=", krypt_asn1_data_set_tag, 1);
1946
+ rb_define_method(cKryptASN1Data, "tag_class", krypt_asn1_data_get_tag_class, 0);
1947
+ rb_define_method(cKryptASN1Data, "tag_class=", krypt_asn1_data_set_tag_class, 1);
1948
+ rb_define_method(cKryptASN1Data, "infinite_length", krypt_asn1_data_get_inf_length, 0);
1949
+ rb_define_method(cKryptASN1Data, "infinite_length=", krypt_asn1_data_set_inf_length, 1);
1950
+ rb_define_method(cKryptASN1Data, "value", krypt_asn1_data_get_value, 0);
1951
+ rb_define_method(cKryptASN1Data, "value=", krypt_asn1_data_set_value, 1);
1952
+ rb_define_method(cKryptASN1Data, "to_der", krypt_asn1_data_to_der, 0);
1953
+ rb_define_method(cKryptASN1Data, "encode_to", krypt_asn1_data_encode_to, 1);
1954
+ rb_define_method(cKryptASN1Data, "<=>", krypt_asn1_data_cmp, 1);
1955
+
1956
+ /* Document-class: Krypt::ASN1::Primitive
1957
+ *
1958
+ * The parent class for all primitive encodings. Attributes are the same as
1959
+ * for ASN1Data.
1960
+ * Primitive values can never be infinite length encodings, thus it is not
1961
+ * possible to set the +infinite_length+ attribute for Primitive and its
1962
+ * sub-classes.
1963
+ *
1964
+ * == Primitive sub-classes and their mapping to Ruby classes
1965
+ * * Krypt::ASN1::EndOfContents <=> +value+ is always +nil+
1966
+ * * Krypt::ASN1::Boolean <=> +value+ is a +Boolean+
1967
+ * * Krypt::ASN1::Integer <=> +value+ is a +Number+
1968
+ * * Krypt::ASN1::BitString <=> +value+ is a +String+
1969
+ * * Krypt::ASN1::OctetString <=> +value+ is a +String+
1970
+ * * Krypt::ASN1::Null <=> +value+ is always +nil+
1971
+ * * Krypt::ASN1::Object <=> +value+ is a +String+
1972
+ * * Krypt::ASN1::Enumerated <=> +value+ is a +Number+
1973
+ * * Krypt::ASN1::UTF8String <=> +value+ is a +String+
1974
+ * * Krypt::ASN1::NumericString <=> +value+ is a +String+
1975
+ * * Krypt::ASN1::PrintableString <=> +value+ is a +String+
1976
+ * * Krypt::ASN1::T61String <=> +value+ is a +String+
1977
+ * * Krypt::ASN1::VideotexString <=> +value+ is a +String+
1978
+ * * Krypt::ASN1::IA5String <=> +value+ is a +String+
1979
+ * * Krypt::ASN1::UTCTime <=> +value+ is a +Time+ (or a Number when creating them)
1980
+ * * Krypt::ASN1::GeneralizedTime <=> +value+ is a +Time+ (or a Number when creating them)
1981
+ * * Krypt::ASN1::GraphicString <=> +value+ is a +String+
1982
+ * * Krypt::ASN1::ISO64String <=> +value+ is a +String+
1983
+ * * Krypt::ASN1::GeneralString <=> +value+ is a +String+
1984
+ * * Krypt::ASN1::UniversalString <=> +value+ is a +String+
1985
+ * * Krypt::ASN1::BMPString <=> +value+ is a +String+
1986
+ *
1987
+ * == Krypt::ASN1::BitString
1988
+ *
1989
+ * === Additional attribute
1990
+ * +unused_bits+: if the underlying BIT STRING's
1991
+ * length is a multiple of 8 then +unused_bits+ is 0. Otherwise
1992
+ * +unused_bits+ indicates the number of bits that are to be ignored in
1993
+ * the final octet of the +BitString+'s +value+.
1994
+ *
1995
+ * == Examples
1996
+ * With the Exception of Krypt::ASN1::EndOfContents and Krypt::ASN1::Null,
1997
+ * each Primitive class constructor takes at least one parameter, the
1998
+ * +value+. Since the value of the former two is always +nil+, they also
1999
+ * support a no-arg constructor.
2000
+ *
2001
+ * === Creating EndOfContents and Null
2002
+ * eoc = Krypt::ASN1::EndOfContents.new
2003
+ * null = Krypt::ASN1::Null.new
2004
+ *
2005
+ * === Creating any other Primitive
2006
+ * prim = <class>.new(value) # <class> being one of the sub-classes except EndOfContents of Null
2007
+ * prim_zero_context = <class>.new(value, 0, :CONTEXT_SPECIFIC)
2008
+ * prim_zero_private = <class>.new(value, 0, :PRIVATE)
2009
+ */
2010
+ cKryptASN1Primitive = rb_define_class_under(mKryptASN1, "Primitive", cKryptASN1Data);
2011
+ rb_define_method(cKryptASN1Primitive, "initialize", krypt_asn1_data_initialize, 3);
2012
+
2013
+ /* Document-class: Krypt::ASN1::Constructive
2014
+ *
2015
+ * The parent class for all constructed encodings. The +value+ attribute
2016
+ * of a parsed Constructive is always an +Array+. Attributes are the same as
2017
+ * for ASN1Data.
2018
+ *
2019
+ * == SET and SEQUENCE
2020
+ *
2021
+ * Most constructed encodings come in the form of a SET or a SEQUENCE.
2022
+ * These encodings are represented by one of the two sub-classes of
2023
+ * Constructive:
2024
+ * * Krypt::ASN1::Set
2025
+ * * Krypt::ASN1::Sequence
2026
+ * Please note that tagged sequences and sets are still parsed as
2027
+ * instances of ASN1Data. Find further details on tagged values
2028
+ * there.
2029
+ *
2030
+ * === Example - constructing a SEQUENCE
2031
+ * int = Krypt::ASN1::Integer.new(1)
2032
+ * str = Krypt::ASN1::PrintableString.new('abc')
2033
+ * sequence = Krypt::ASN1::Sequence.new( [ int, str ] )
2034
+ *
2035
+ * === Example - constructing a SET
2036
+ * int = Krypt::ASN1::Integer.new(1)
2037
+ * str = Krypt::ASN1::PrintableString.new('abc')
2038
+ * set = Krypt::ASN1::Set.new( [ int, str ] )
2039
+ *
2040
+ * == Infinite length primitive values
2041
+ *
2042
+ * The only case where Constructive is used directly is for infinite
2043
+ * length encodings of primitive values. These encodings are always
2044
+ * constructed, with the contents of the +value+ +Array+ being either
2045
+ * UNIVERSAL non-infinite length partial encodings of the actual value
2046
+ * or again constructive encodings with infinite length (i.e. infinite
2047
+ * length primitive encodings may be constructed recursively with another
2048
+ * infinite length value within an already infinite length value). Each
2049
+ * partial encoding must be of the same UNIVERSAL type as the overall
2050
+ * encoding. The value of the overall encoding consists of the
2051
+ * concatenation of each partial encoding taken in sequence. The +value+
2052
+ * array of the outer infinite length value must end with a
2053
+ * Krypt::ASN1::EndOfContents instance.
2054
+ *
2055
+ * === Example - Infinite length OCTET STRING
2056
+ * partial1 = Krypt::ASN1::OctetString.new("\x01")
2057
+ * partial2 = Krypt::ASN1::OctetString.new("\x02")
2058
+ * inf_octets = Krypt::ASN1::OctetString.new( [ partial1,
2059
+ * partial2,
2060
+ * Krypt::ASN1::EndOfContent.new ])
2061
+ * # The real value of inf_octets is "\x01\x02", i.e. the concatenation
2062
+ * # of partial1 and partial2
2063
+ * inf_octets.infinite_length = true
2064
+ * der = inf_octets.to_der
2065
+ * asn1 = Krypt::ASN1.decode(der)
2066
+ * puts asn1.infinite_length # => true
2067
+ */
2068
+ cKryptASN1Constructive = rb_define_class_under(mKryptASN1, "Constructive", cKryptASN1Data);
2069
+ rb_include_module(cKryptASN1Constructive, rb_mEnumerable);
2070
+ rb_define_method(cKryptASN1Constructive, "initialize", krypt_asn1_data_initialize, 3);
2071
+ rb_define_method(cKryptASN1Constructive, "each", krypt_asn1_cons_each, 0);
2072
+
2073
+ #define KRYPT_ASN1_DEFINE_CLASS(name, super, init) \
2074
+ cKryptASN1##name = rb_define_class_under(mKryptASN1, #name, cKryptASN1##super); \
2075
+ rb_define_method(cKryptASN1##name, "initialize", krypt_asn1_##init##_initialize, -1);
2076
+
2077
+ KRYPT_ASN1_DEFINE_CLASS(EndOfContents, Primitive, end_of_contents)
2078
+ KRYPT_ASN1_DEFINE_CLASS(Boolean, Primitive, boolean)
2079
+ KRYPT_ASN1_DEFINE_CLASS(Integer, Primitive, integer)
2080
+ KRYPT_ASN1_DEFINE_CLASS(Enumerated, Primitive, enumerated)
2081
+ KRYPT_ASN1_DEFINE_CLASS(BitString, Primitive, bit_string)
2082
+ KRYPT_ASN1_DEFINE_CLASS(OctetString, Primitive, octet_string)
2083
+ KRYPT_ASN1_DEFINE_CLASS(UTF8String, Primitive, utf8_string)
2084
+ KRYPT_ASN1_DEFINE_CLASS(NumericString, Primitive, numeric_string)
2085
+ KRYPT_ASN1_DEFINE_CLASS(PrintableString, Primitive, printable_string)
2086
+ KRYPT_ASN1_DEFINE_CLASS(T61String, Primitive, t61_string)
2087
+ KRYPT_ASN1_DEFINE_CLASS(VideotexString, Primitive, videotex_string)
2088
+ KRYPT_ASN1_DEFINE_CLASS(IA5String, Primitive, ia5_string)
2089
+ KRYPT_ASN1_DEFINE_CLASS(GraphicString, Primitive, graphic_string)
2090
+ KRYPT_ASN1_DEFINE_CLASS(ISO64String, Primitive, iso64_string)
2091
+ KRYPT_ASN1_DEFINE_CLASS(GeneralString, Primitive, general_string)
2092
+ KRYPT_ASN1_DEFINE_CLASS(UniversalString, Primitive, universal_string)
2093
+ KRYPT_ASN1_DEFINE_CLASS(BMPString, Primitive, bmp_string)
2094
+ KRYPT_ASN1_DEFINE_CLASS(Null, Primitive, null)
2095
+ KRYPT_ASN1_DEFINE_CLASS(ObjectId, Primitive, object_id)
2096
+ KRYPT_ASN1_DEFINE_CLASS(UTCTime, Primitive, utc_time)
2097
+ KRYPT_ASN1_DEFINE_CLASS(GeneralizedTime, Primitive, generalized_time)
2098
+ KRYPT_ASN1_DEFINE_CLASS(Sequence, Constructive, sequence)
2099
+ KRYPT_ASN1_DEFINE_CLASS(Set, Constructive, set)
2100
+
2101
+ rb_define_method(cKryptASN1BitString, "unused_bits", krypt_asn1_bit_string_get_unused_bits, 0);
2102
+ rb_define_method(cKryptASN1BitString, "unused_bits=", krypt_asn1_bit_string_set_unused_bits, 1);
2103
+
2104
+ Init_krypt_asn1_parser();
2105
+ Init_krypt_asn1_template();
2106
+ Init_krypt_instream_adapter();
2107
+ Init_krypt_pem();
2108
+ }
2109
+