blob: a6cccec847283e2ed6847b080a4f1b061abcf370 [file] [log] [blame]
vlmfa67ddc2004-06-03 03:38:44 +00001/*-
2 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
5#include <constr_TYPE.h>
6#include <ber_tlv_tag.h>
7#include <errno.h>
8
9ssize_t
10ber_fetch_tag(void *ptr, size_t size, ber_tlv_tag_t *tag_r) {
11 ber_tlv_tag_t val;
12 ber_tlv_tag_t tclass;
vlmb42843a2004-06-05 08:17:50 +000013 size_t skipped;
vlmfa67ddc2004-06-03 03:38:44 +000014
15 if(size == 0)
16 return 0;
17
18 val = *(uint8_t *)ptr;
19 tclass = (val >> 6);
20 if((val &= 31) != 31) {
21 /*
22 * Simple form: everything encoded in a single octet.
23 * Tag Class is encoded using two least significant bits.
24 */
25 *tag_r = (val << 2) | tclass;
26 return 1;
27 }
28
29 /*
30 * Each octet contains 7 bits of useful information.
31 * The MSB is 0 if it is the last octet of the tag.
32 */
33 for(val = 0, ptr++, skipped = 2; skipped < size; ptr++, skipped++) {
34 unsigned oct = *(uint8_t *)ptr;
35 if(oct & 0x80) {
36 val = (val << 7) | (oct & 0x7F);
37 /*
38 * Make sure there are at least 9 bits spare
39 * at the MS side of a value.
40 */
41 if(val >> ((8 * sizeof(val)) - 9)) {
42 /*
43 * We would not be able to accomodate
44 * any more tag bits.
45 */
46 return -1;
47 }
48 } else {
49 *tag_r = (val << 9) | (oct << 2) | tclass;
50 return skipped;
51 }
52 }
53
54 return 0; /* Want more */
55}
56
57
58ssize_t
59ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *f) {
60 char buf[sizeof("[APPLICATION ]") + 32];
61 ssize_t ret;
62
63 ret = ber_tlv_tag_snprint(tag, buf, sizeof(buf));
vlmb42843a2004-06-05 08:17:50 +000064 if(ret >= (ssize_t)sizeof(buf) || ret < 2) {
vlmfa67ddc2004-06-03 03:38:44 +000065 errno = EPERM;
66 return -1;
67 }
68
69 return fwrite(buf, 1, ret, f);
70}
71
72ssize_t
73ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t size) {
74 char *type = 0;
75 int ret;
76
77 switch(tag & 0x3) {
78 case ASN_TAG_CLASS_UNIVERSAL: type = "UNIVERSAL "; break;
79 case ASN_TAG_CLASS_APPLICATION: type = "APPLICATION "; break;
80 case ASN_TAG_CLASS_CONTEXT: type = ""; break;
81 case ASN_TAG_CLASS_PRIVATE: type = "PRIVATE "; break;
82 }
83
84 ret = snprintf(buf, size, "[%s%u]", type, ((unsigned)tag) >> 2);
85 if(ret <= 0 && size) buf[0] = '\0'; /* against broken libc's */
86
87 return ret;
88}
89
90char *
91ber_tlv_tag_string(ber_tlv_tag_t tag) {
92 static char buf[sizeof("[APPLICATION ]") + 32];
93
94 (void)ber_tlv_tag_snprint(tag, buf, sizeof(buf));
95
96 return buf;
97}
98
99
100ssize_t
101der_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufp, size_t size) {
102 int tclass = BER_TAG_CLASS(tag);
103 ber_tlv_tag_t tval = BER_TAG_VALUE(tag);
104 uint8_t *buf = bufp;
105 uint8_t *end;
vlmb42843a2004-06-05 08:17:50 +0000106 size_t computed_size;
vlmfa67ddc2004-06-03 03:38:44 +0000107 int i;
108
109 if(tval <= 30) {
110 /* Encoded in 1 octet */
111 if(size) buf[0] = (tclass << 6) | tval;
112 return 1;
113 } else if(size) {
114 *buf++ = (tclass << 6) | 0x1F;
115 size--;
116 }
117
118 /*
119 * Compute the size of the subsequent bytes.
120 * The routine is written so every floating-point
121 * operation is done at compile time.
122 * Note, there is a subtle problem lurking here,
123 * could you guess where it is? :)
124 * Hint: what happens when ((8*sizeof(tag))%7) == 0?
125 */
126 computed_size = 1 + 8 * sizeof(tag) / 7;
127 for(i = (8*sizeof(tag)) - ((8*sizeof(tag))%7); i >= 7; i -= 7) {
128 if((tval >> i) & 0x7F) break;
129 computed_size--;
130 }
131
132 /*
133 * Fill in the buffer, space permitting.
134 */
135 if(size > computed_size)
136 end = buf + computed_size;
137 else
138 end = buf + size;
139 for((void)i; buf < end; i -= 7, buf++) {
140 *buf = 0x80 | ((tval>>i) & 0x7F);
141 }
142
143 return computed_size + 1;
144}
145