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,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
+