krypt-core 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/ext/krypt/core/Makefile +221 -0
- data/ext/krypt/core/binyo-error.h +40 -0
- data/ext/krypt/core/binyo-io-buffer.h +54 -0
- data/ext/krypt/core/binyo-io.h +131 -0
- data/ext/krypt/core/extconf.h +8 -0
- data/ext/krypt/core/extconf.rb +80 -0
- data/ext/krypt/core/krypt-core.c +110 -0
- data/ext/krypt/core/krypt-core.h +97 -0
- data/ext/krypt/core/krypt-core.o +0 -0
- data/ext/krypt/core/krypt-provider.h +86 -0
- data/ext/krypt/core/krypt_asn1-internal.c +681 -0
- data/ext/krypt/core/krypt_asn1-internal.h +117 -0
- data/ext/krypt/core/krypt_asn1-internal.o +0 -0
- data/ext/krypt/core/krypt_asn1.c +2109 -0
- data/ext/krypt/core/krypt_asn1.h +88 -0
- data/ext/krypt/core/krypt_asn1.o +0 -0
- data/ext/krypt/core/krypt_asn1_codec.c +973 -0
- data/ext/krypt/core/krypt_asn1_codec.o +0 -0
- data/ext/krypt/core/krypt_asn1_in_adapter.c +178 -0
- data/ext/krypt/core/krypt_asn1_in_adapter.o +0 -0
- data/ext/krypt/core/krypt_asn1_in_chunked.c +292 -0
- data/ext/krypt/core/krypt_asn1_in_chunked.o +0 -0
- data/ext/krypt/core/krypt_asn1_in_definite.c +156 -0
- data/ext/krypt/core/krypt_asn1_in_definite.o +0 -0
- data/ext/krypt/core/krypt_asn1_parser.c +592 -0
- data/ext/krypt/core/krypt_asn1_parser.o +0 -0
- data/ext/krypt/core/krypt_asn1_template-internal.h +185 -0
- data/ext/krypt/core/krypt_asn1_template.c +459 -0
- data/ext/krypt/core/krypt_asn1_template.h +56 -0
- data/ext/krypt/core/krypt_asn1_template.o +0 -0
- data/ext/krypt/core/krypt_asn1_template_encoder.c +76 -0
- data/ext/krypt/core/krypt_asn1_template_encoder.o +0 -0
- data/ext/krypt/core/krypt_asn1_template_parser.c +1176 -0
- data/ext/krypt/core/krypt_asn1_template_parser.o +0 -0
- data/ext/krypt/core/krypt_b64-internal.h +38 -0
- data/ext/krypt/core/krypt_b64.c +391 -0
- data/ext/krypt/core/krypt_b64.h +41 -0
- data/ext/krypt/core/krypt_b64.o +0 -0
- data/ext/krypt/core/krypt_digest.c +391 -0
- data/ext/krypt/core/krypt_digest.h +51 -0
- data/ext/krypt/core/krypt_digest.o +0 -0
- data/ext/krypt/core/krypt_error.c +221 -0
- data/ext/krypt/core/krypt_error.h +46 -0
- data/ext/krypt/core/krypt_error.o +0 -0
- data/ext/krypt/core/krypt_hex-internal.h +36 -0
- data/ext/krypt/core/krypt_hex.c +255 -0
- data/ext/krypt/core/krypt_hex.h +41 -0
- data/ext/krypt/core/krypt_hex.o +0 -0
- data/ext/krypt/core/krypt_io.c +65 -0
- data/ext/krypt/core/krypt_io.h +56 -0
- data/ext/krypt/core/krypt_io.o +0 -0
- data/ext/krypt/core/krypt_io_in_pem.c +397 -0
- data/ext/krypt/core/krypt_io_in_pem.o +0 -0
- data/ext/krypt/core/krypt_missing.c +238 -0
- data/ext/krypt/core/krypt_missing.h +62 -0
- data/ext/krypt/core/krypt_missing.o +0 -0
- data/ext/krypt/core/krypt_pem.c +171 -0
- data/ext/krypt/core/krypt_pem.o +0 -0
- data/ext/krypt/core/krypt_provider-internal.h +40 -0
- data/ext/krypt/core/krypt_provider.c +136 -0
- data/ext/krypt/core/krypt_provider.o +0 -0
- data/ext/krypt/core/kryptcore.so +0 -0
- data/ext/krypt/core/mkmf.log +130 -0
- data/lib/krypt-core/version.rb +3 -0
- data/lib/krypt-core.rb +35 -0
- data/lib/kryptcore.so +0 -0
- data/spec/README +2 -0
- data/test/README +2 -0
- data/test/res/certificate.cer +0 -0
- data/test/resources.rb +48 -0
- data/test/scratch.rb +17 -0
- metadata +150 -0
@@ -0,0 +1,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
|
+
|