ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-BER-XS/XS.xs
Revision: 1.1
Committed: Fri Apr 19 16:19:36 2019 UTC (5 years, 1 month ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 // C99 required
6
7 enum {
8 // ASN_TAG
9 ASN_BOOLEAN = 0x01,
10 ASN_INTEGER32 = 0x02,
11 ASN_BIT_STRING = 0x03,
12 ASN_OCTET_STRING = 0x04,
13 ASN_NULL = 0x05,
14 ASN_OBJECT_IDENTIFIER = 0x06,
15 ASN_SEQUENCE = 0x10,
16
17 ASN_TAG_BER = 0x1f,
18 ASN_TAG_MASK = 0x1f,
19
20 // primitive/constructed
21 ASN_CONSTRUCTED = 0x20,
22
23 // ASN_CLASS
24 ASN_UNIVERSAL = 0x00,
25 ASN_APPLICATION = 0x40,
26 ASN_CONTEXT = 0x80,
27 ASN_PRIVATE = 0xc0,
28
29 ASN_CLASS_MASK = 0xc0,
30 ASN_CLASS_SHIFT = 6,
31
32 // ASN_APPLICATION
33 ASN_IPADDRESS = 0x00,
34 ASN_COUNTER32 = 0x01,
35 ASN_UNSIGNED32 = 0x02,
36 ASN_TIMETICKS = 0x03,
37 ASN_OPAQUE = 0x04,
38 ASN_COUNTER64 = 0x06,
39 };
40
41 enum {
42 BER_CLASS = 0,
43 BER_TAG = 1,
44 BER_CONSTRUCTED = 2,
45 BER_DATA = 3,
46 BER_ARRAYSIZE
47 };
48
49 #define MAX_OID_STRLEN 4096
50
51 static U8 *buf, *cur;
52 static STRLEN len, rem;
53
54 // for "small" integers, return a readonly sv, otherwise create a new one
55 static SV *newSVcacheint (int val)
56 {
57 static SV *cache[32];
58
59 if (val < 0 || val >= sizeof (cache))
60 return newSViv (val);
61
62 if (!cache [val])
63 {
64 cache [val] = newSVuv (val);
65 SvREADONLY_on (cache [val]);
66 }
67
68 return SvREFCNT_inc_NN (cache [val]);
69 }
70
71 /////////////////////////////////////////////////////////////////////////////
72
73 static void
74 error (const char *errmsg)
75 {
76 croak ("%s at offset 0x%04x", errmsg, cur - buf);
77 }
78
79 static int
80 need (int count)
81 {
82 if (count < 0 || (int)rem < count)
83 {
84 error ("unexpected end of message buffer");
85 return 0;
86 }
87
88 return 1;
89 }
90
91 static U8 *
92 getn (int count, const U8 *errres)
93 {
94 if (!need (count))
95 return (U8 *)errres;
96
97 U8 *res = cur;
98
99 cur += count;
100 rem -= count;
101
102 return res;
103 }
104
105 static U8
106 get8 (void)
107 {
108 if (rem <= 0)
109 {
110 error ("unexpected end of message buffer");
111 return 0;
112 }
113
114 rem--;
115 return *cur++;
116 }
117
118 static U32
119 getb (void)
120 {
121 U32 res = 0;
122
123 for (;;)
124 {
125 U8 c = get8 ();
126 res = (res << 7) | (c & 0x7f);
127
128 if (!(c & 0x80))
129 return res;
130 }
131 }
132
133 static U32
134 process_length (void)
135 {
136 U32 res = get8 ();
137
138 if (res & 0x80)
139 {
140 int cnt = res & 0x7f;
141 res = 0;
142
143 switch (cnt)
144 {
145 case 0:
146 error ("indefinite ASN.1 lengths not supported");
147 return 0;
148
149 default:
150 error ("ASN.1 length too long");
151 return 0;
152
153 case 4: res = (res << 8) | get8 ();
154 case 3: res = (res << 8) | get8 ();
155 case 2: res = (res << 8) | get8 ();
156 case 1: res = (res << 8) | get8 ();
157 }
158 }
159
160 return res;
161 }
162
163 static U32
164 process_integer32 (void)
165 {
166 U32 length = process_length ();
167
168 if (length <= 0)
169 {
170 error ("INTEGER32 length equal to zero");
171 return 0;
172 }
173
174 U8 *data = getn (length, 0);
175
176 if (!data)
177 return 0;
178
179 if (length > 5 || (length > 4 && data [0]))
180 {
181 error ("INTEGER32 length too long");
182 return 0;
183 }
184
185 U32 res = data [0] & 0x80 ? 0xffffffff : 0;
186
187 while (length--)
188 res = (res << 8) | *data++;
189
190 return res;
191 }
192
193 static SV *
194 process_integer32_sv (void)
195 {
196 return newSViv ((I32)process_integer32 ());
197 }
198
199 static SV *
200 process_unsigned32_sv (void)
201 {
202 return newSVuv ((U32)process_integer32 ());
203 }
204
205 #if IVSIZE >= 8
206
207 static U64TYPE
208 process_integer64 (void)
209 {
210 U32 length = process_length ();
211
212 if (length <= 0)
213 {
214 error ("INTEGER64 length equal to zero");
215 return 0;
216 }
217
218 U8 *data = getn (length, 0);
219
220 if (!data)
221 return 0;
222
223 if (length > 9 || (length > 8 && data [0]))
224 {
225 error ("INTEGER64 length too long");
226 return 0;
227 }
228
229 U64TYPE res = data [0] & 0x80 ? 0xffffffffffffffff : 0;
230
231 while (length--)
232 res = (res << 8) | *data++;
233
234 return res;
235 }
236
237 static SV *
238 process_integer64_sv (void)
239 {
240 return newSViv ((I64TYPE)process_integer64 ());
241 }
242
243 static SV *
244 process_unsigned64_sv (void)
245 {
246 return newSVuv ((U64TYPE)process_integer64 ());
247 }
248
249 #endif
250
251 static SV *
252 process_octet_string_sv (void)
253 {
254 U32 length = process_length ();
255
256 U8 *data = getn (length, 0);
257 if (!data)
258 {
259 error ("OCTET STRING too long");
260 return &PL_sv_undef;
261 }
262
263 return newSVpvn (data, length);
264 }
265
266 static char *
267 write_uv (char *buf, U32 u)
268 {
269 // the one-digit case is absolutely predominant, so this pays off (hopefully)
270 if (u < 10)
271 *buf++ = u + '0';
272 else
273 {
274 char *beg = buf;
275
276 do
277 {
278 *buf++ = u % 10 + '0';
279 u /= 10;
280 }
281 while (u);
282
283 // reverse digits
284 for (char *ptr = buf; --ptr != beg; ++beg)
285 {
286 char c = *ptr;
287 *ptr = *beg;
288 *beg = c;
289 }
290 }
291
292 return buf;
293 }
294
295 static SV *
296 process_object_identifier_sv (void)
297 {
298 U32 length = process_length ();
299
300 if (length <= 0)
301 {
302 error ("OBJECT IDENTIFIER length equal to zero");
303 return &PL_sv_undef;
304 }
305
306 U8 *end = cur + length;
307 U32 w = getb ();
308
309 static char oid[MAX_OID_STRLEN]; // must be static
310 char *app = oid;
311
312 app = write_uv (app, (U8)w / 40);
313 *app++ = '.';
314 app = write_uv (app, (U8)w % 40);
315
316 // we assume an oid component is never > 64 bytes
317 while (cur < end && oid + sizeof (oid) - app > 64)
318 {
319 w = getb ();
320 *app++ = '.';
321 app = write_uv (app, w);
322 }
323
324 return newSVpvn (oid, app - oid);
325 }
326
327 static SV *
328 ber_decode ()
329 {
330 int identifier = get8 ();
331
332 SV *res;
333
334 int constructed = identifier & ASN_CONSTRUCTED;
335 int klass = identifier & ASN_CLASS_MASK;
336 int tag = identifier & ASN_TAG_MASK;
337
338 if (tag == ASN_TAG_BER)
339 tag = getb ();
340
341 if (tag == ASN_TAG_BER)
342 tag = getb ();
343
344 if (constructed)
345 {
346 U32 len = process_length ();
347 U32 seqend = (cur - buf) + len;
348 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
349
350 while (cur < buf + seqend)
351 av_push (av, ber_decode ());
352
353 if (cur > buf + seqend)
354 croak ("constructed type %02x overflow (%x %x)\n", identifier, cur - buf, seqend);
355
356 res = newRV_inc ((SV *)av);
357 }
358 else
359 switch (identifier)
360 {
361 case ASN_NULL:
362 res = &PL_sv_undef;
363 break;
364
365 case ASN_OBJECT_IDENTIFIER:
366 res = process_object_identifier_sv ();
367 break;
368
369 case ASN_INTEGER32:
370 res = process_integer32_sv ();
371 break;
372
373 case ASN_APPLICATION | ASN_UNSIGNED32:
374 case ASN_APPLICATION | ASN_COUNTER32:
375 case ASN_APPLICATION | ASN_TIMETICKS:
376 res = process_unsigned32_sv ();
377 break;
378
379 #if 0 // handled by default case
380 case ASN_OCTET_STRING:
381 case ASN_APPLICATION | ASN_IPADDRESS:
382 case ASN_APPLICATION | ASN_OPAQUE:
383 res = process_octet_string_sv ();
384 break;
385 #endif
386
387 case ASN_APPLICATION | ASN_COUNTER64:
388 res = process_integer64_sv ();
389 break;
390
391 default:
392 res = process_octet_string_sv ();
393 break;
394 }
395
396 AV *av = newAV ();
397 av_fill (av, BER_ARRAYSIZE - 1);
398 AvARRAY (av)[BER_CLASS ] = newSVcacheint (klass >> ASN_CLASS_SHIFT);
399 AvARRAY (av)[BER_TAG ] = newSVcacheint (tag);
400 AvARRAY (av)[BER_CONSTRUCTED] = newSVcacheint (constructed ? 1 : 0);
401 AvARRAY (av)[BER_DATA ] = res;
402
403 return newRV_noinc ((SV *)av);
404 }
405
406 MODULE = Convert::BER::XS PACKAGE = Convert::BER::XS
407
408 PROTOTYPES: ENABLE
409
410 BOOT:
411 {
412 HV *stash = gv_stashpv ("Convert::BER::XS", 1);
413
414 static const struct {
415 const char *name;
416 IV iv;
417 } *civ, const_iv[] = {
418 { "ASN_BOOLEAN", ASN_BOOLEAN },
419 { "ASN_INTEGER32", ASN_INTEGER32 },
420 { "ASN_BIT_STRING", ASN_BIT_STRING },
421 { "ASN_OCTET_STRING", ASN_OCTET_STRING },
422 { "ASN_NULL", ASN_NULL },
423 { "ASN_OBJECT_IDENTIFIER", ASN_OBJECT_IDENTIFIER },
424 { "ASN_TAG_BER", ASN_TAG_BER },
425 { "ASN_TAG_MASK", ASN_TAG_MASK },
426 { "ASN_CONSTRUCTED", ASN_CONSTRUCTED },
427 { "ASN_UNIVERSAL", ASN_UNIVERSAL >> ASN_CLASS_SHIFT },
428 { "ASN_APPLICATION", ASN_APPLICATION >> ASN_CLASS_SHIFT },
429 { "ASN_CONTEXT", ASN_CONTEXT >> ASN_CLASS_SHIFT },
430 { "ASN_PRIVATE", ASN_PRIVATE >> ASN_CLASS_SHIFT },
431 { "ASN_CLASS_MASK", ASN_CLASS_MASK },
432 { "ASN_CLASS_SHIFT", ASN_CLASS_SHIFT },
433 { "ASN_SEQUENCE", ASN_SEQUENCE },
434 { "ASN_IPADDRESS", ASN_IPADDRESS },
435 { "ASN_COUNTER32", ASN_COUNTER32 },
436 { "ASN_UNSIGNED32", ASN_UNSIGNED32 },
437 { "ASN_TIMETICKS", ASN_TIMETICKS },
438 { "ASN_OPAQUE", ASN_OPAQUE },
439 { "ASN_COUNTER64", ASN_COUNTER64 },
440
441 { "BER_CLASS" , BER_CLASS },
442 { "BER_TAG" , BER_TAG },
443 { "BER_CONSTRUCTED", BER_CONSTRUCTED },
444 { "BER_DATA" , BER_DATA },
445 };
446
447 for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ > const_iv; civ--)
448 newCONSTSUB (stash, (char *)civ[-1].name, newSViv (civ[-1].iv));
449 }
450
451 SV *
452 ber_decode (SV *ber)
453 CODE:
454 {
455 buf = SvPVbyte (ber, len);
456 cur = buf;
457 rem = len;
458
459 RETVAL = ber_decode ();
460 }
461 OUTPUT: RETVAL
462
463 void
464 ber_is (SV *tuple, SV *klass = &PL_sv_undef, SV *tag = &PL_sv_undef, SV *constructed = &PL_sv_undef, SV *data = &PL_sv_undef)
465 PROTOTYPE: $;$$$
466 PPCODE:
467 {
468 if (!SvOK (tuple))
469 XSRETURN_NO;
470
471 if (!SvROK (tuple) || SvTYPE (SvRV (tuple)) != SVt_PVAV)
472 croak ("ber_seq: tuple must be ber tuple (array-ref)");
473
474 AV *av = (AV *)SvRV (tuple);
475
476 XPUSHs (
477 (!SvOK (klass) || SvIV (AvARRAY (av)[BER_CLASS ]) == SvIV (klass))
478 && (!SvOK (tag) || SvIV (AvARRAY (av)[BER_TAG ]) == SvIV (tag))
479 && (!SvOK (constructed) || !SvIV (AvARRAY (av)[BER_CONSTRUCTED]) == !SvIV (constructed))
480 && (!SvOK (data) || sv_eq (AvARRAY (av)[BER_DATA ], data))
481 ? &PL_sv_yes : &PL_sv_no);
482 }
483
484 void
485 ber_is_seq (SV *tuple)
486 PROTOTYPE: $
487 PPCODE:
488 {
489 if (!SvOK (tuple))
490 XSRETURN_UNDEF;
491
492 if (!SvROK (tuple) || SvTYPE (SvRV (tuple)) != SVt_PVAV)
493 croak ("ber_seq: tuple must be ber tuple (array-ref)");
494
495 AV *av = (AV *)SvRV (tuple);
496
497 XPUSHs (
498 SvIV (AvARRAY (av)[BER_CLASS ]) == ASN_UNIVERSAL
499 && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_SEQUENCE
500 && SvIV (AvARRAY (av)[BER_CONSTRUCTED])
501 ? AvARRAY (av)[BER_DATA] : &PL_sv_undef);
502 }
503
504 void
505 ber_is_i32 (SV *tuple, IV value)
506 PROTOTYPE: $$
507 PPCODE:
508 {
509 if (!SvOK (tuple))
510 XSRETURN_NO;
511
512 if (!SvROK (tuple) || SvTYPE (SvRV (tuple)) != SVt_PVAV)
513 croak ("ber_seq: tuple must be ber tuple (array-ref)");
514
515 AV *av = (AV *)SvRV (tuple);
516
517 XPUSHs (
518 SvIV (AvARRAY (av)[BER_CLASS ]) == ASN_UNIVERSAL
519 && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_INTEGER32
520 && !SvIV (AvARRAY (av)[BER_CONSTRUCTED])
521 && SvIV (AvARRAY (av)[BER_DATA ]) == value
522 ? &PL_sv_yes : &PL_sv_no);
523 }
524
525 void
526 ber_is_oid (SV *tuple, SV *oid)
527 PROTOTYPE: $$
528 PPCODE:
529 {
530 if (!SvOK (tuple))
531 XSRETURN_NO;
532
533 if (!SvROK (tuple) || SvTYPE (SvRV (tuple)) != SVt_PVAV)
534 croak ("ber_seq: tuple must be ber tuple (array-ref)");
535
536 AV *av = (AV *)SvRV (tuple);
537
538 XPUSHs (
539 SvIV (AvARRAY (av)[BER_CLASS ]) == ASN_UNIVERSAL
540 && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_OBJECT_IDENTIFIER
541 && !SvIV (AvARRAY (av)[BER_CONSTRUCTED])
542 && sv_eq (AvARRAY (av)[BER_DATA], oid)
543 ? &PL_sv_yes : &PL_sv_no);
544 }
545