~ubuntu-branches/ubuntu/quantal/freerdp/quantal

« back to all changes in this revision

Viewing changes to asn1/der_encoder.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2010-06-23 21:39:09 UTC
  • Revision ID: james.westby@ubuntu.com-20100623213909-bb9pvvv03913tdv6
Tags: upstream-0.7.1
ImportĀ upstreamĀ versionĀ 0.7.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
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 <asn_internal.h>
 
6
#include <errno.h>
 
7
 
 
8
static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
 
9
        asn_app_consume_bytes_f *cb, void *app_key, int constructed);
 
10
 
 
11
/*
 
12
 * The DER encoder of any type.
 
13
 */
 
14
asn_enc_rval_t
 
15
der_encode(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
 
16
        asn_app_consume_bytes_f *consume_bytes, void *app_key) {
 
17
 
 
18
        ASN_DEBUG("DER encoder invoked for %s",
 
19
                type_descriptor->name);
 
20
 
 
21
        /*
 
22
         * Invoke type-specific encoder.
 
23
         */
 
24
        return type_descriptor->der_encoder(type_descriptor,
 
25
                struct_ptr,     /* Pointer to the destination structure */
 
26
                0, 0,
 
27
                consume_bytes, app_key);
 
28
}
 
29
 
 
30
/*
 
31
 * Argument type and callback necessary for der_encode_to_buffer().
 
32
 */
 
33
typedef struct enc_to_buf_arg {
 
34
        void *buffer;
 
35
        size_t left;
 
36
} enc_to_buf_arg;
 
37
static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) {
 
38
        enc_to_buf_arg *arg = (enc_to_buf_arg *)key;
 
39
 
 
40
        if(arg->left < size)
 
41
                return -1;      /* Data exceeds the available buffer size */
 
42
 
 
43
        memcpy(arg->buffer, buffer, size);
 
44
        arg->buffer = ((char *)arg->buffer) + size;
 
45
        arg->left -= size;
 
46
 
 
47
        return 0;
 
48
}
 
49
 
 
50
/*
 
51
 * A variant of the der_encode() which encodes the data into the provided buffer
 
52
 */
 
53
asn_enc_rval_t
 
54
der_encode_to_buffer(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
 
55
        void *buffer, size_t buffer_size) {
 
56
        enc_to_buf_arg arg;
 
57
        asn_enc_rval_t ec;
 
58
 
 
59
        arg.buffer = buffer;
 
60
        arg.left = buffer_size;
 
61
 
 
62
        ec = type_descriptor->der_encoder(type_descriptor,
 
63
                struct_ptr,     /* Pointer to the destination structure */
 
64
                0, 0, encode_to_buffer_cb, &arg);
 
65
        if(ec.encoded != -1) {
 
66
                assert(ec.encoded == (ssize_t)(buffer_size - arg.left));
 
67
                /* Return the encoded contents size */
 
68
        }
 
69
        return ec;
 
70
}
 
71
 
 
72
 
 
73
/*
 
74
 * Write out leading TL[v] sequence according to the type definition.
 
75
 */
 
76
ssize_t
 
77
der_write_tags(asn_TYPE_descriptor_t *sd,
 
78
                size_t struct_length,
 
79
                int tag_mode, int last_tag_form,
 
80
                ber_tlv_tag_t tag,      /* EXPLICIT or IMPLICIT tag */
 
81
                asn_app_consume_bytes_f *cb,
 
82
                void *app_key) {
 
83
        ber_tlv_tag_t *tags;    /* Copy of tags stream */
 
84
        int tags_count;         /* Number of tags */
 
85
        size_t overall_length;
 
86
        ssize_t *lens;
 
87
        int i;
 
88
 
 
89
        ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)",
 
90
                sd->name, tag_mode, sd->tags_count,
 
91
                ber_tlv_tag_string(tag),
 
92
                tag_mode
 
93
                        ?(sd->tags_count+1
 
94
                                -((tag_mode == -1) && sd->tags_count))
 
95
                        :sd->tags_count
 
96
        );
 
97
 
 
98
        if(tag_mode) {
 
99
                /*
 
100
                 * Instead of doing shaman dance like we do in ber_check_tags(),
 
101
                 * allocate a small array on the stack
 
102
                 * and initialize it appropriately.
 
103
                 */
 
104
                int stag_offset;
 
105
                tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t));
 
106
                if(!tags) {     /* Can fail on !x86 */
 
107
                        errno = ENOMEM;
 
108
                        return -1;
 
109
                }
 
110
                tags_count = sd->tags_count
 
111
                        + 1     /* EXPLICIT or IMPLICIT tag is given */
 
112
                        - ((tag_mode == -1) && sd->tags_count);
 
113
                /* Copy tags over */
 
114
                tags[0] = tag;
 
115
                stag_offset = -1 + ((tag_mode == -1) && sd->tags_count);
 
116
                for(i = 1; i < tags_count; i++)
 
117
                        tags[i] = sd->tags[i + stag_offset];
 
118
        } else {
 
119
                tags = sd->tags;
 
120
                tags_count = sd->tags_count;
 
121
        }
 
122
 
 
123
        /* No tags to write */
 
124
        if(tags_count == 0)
 
125
                return 0;
 
126
 
 
127
        lens = (ssize_t *)alloca(tags_count * sizeof(lens[0]));
 
128
        if(!lens) {
 
129
                errno = ENOMEM;
 
130
                return -1;
 
131
        }
 
132
 
 
133
        /*
 
134
         * Array of tags is initialized.
 
135
         * Now, compute the size of the TLV pairs, from right to left.
 
136
         */
 
137
        overall_length = struct_length;
 
138
        for(i = tags_count - 1; i >= 0; --i) {
 
139
                lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0);
 
140
                if(lens[i] == -1) return -1;
 
141
                overall_length += lens[i];
 
142
                lens[i] = overall_length - lens[i];
 
143
        }
 
144
 
 
145
        if(!cb) return overall_length - struct_length;
 
146
 
 
147
        ASN_DEBUG("%s %s TL sequence (%d elements)",
 
148
                cb?"Encoding":"Estimating", sd->name, tags_count);
 
149
 
 
150
        /*
 
151
         * Encode the TL sequence for real.
 
152
         */
 
153
        for(i = 0; i < tags_count; i++) {
 
154
                ssize_t len;
 
155
                int _constr;
 
156
 
 
157
                /* Check if this tag happens to be constructed */
 
158
                _constr = (last_tag_form || i < (tags_count - 1));
 
159
 
 
160
                len = der_write_TL(tags[i], lens[i], cb, app_key, _constr);
 
161
                if(len == -1) return -1;
 
162
        }
 
163
 
 
164
        return overall_length - struct_length;
 
165
}
 
166
 
 
167
static ssize_t
 
168
der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
 
169
                asn_app_consume_bytes_f *cb, void *app_key,
 
170
                int constructed) {
 
171
        uint8_t buf[32];
 
172
        size_t size = 0;
 
173
        int buf_size = cb?sizeof(buf):0;
 
174
        ssize_t tmp;
 
175
 
 
176
        /* Serialize tag (T from TLV) into possibly zero-length buffer */
 
177
        tmp = ber_tlv_tag_serialize(tag, buf, buf_size);
 
178
        if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1;
 
179
        size += tmp;
 
180
 
 
181
        /* Serialize length (L from TLV) into possibly zero-length buffer */
 
182
        tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0);
 
183
        if(tmp == -1) return -1;
 
184
        size += tmp;
 
185
 
 
186
        if(size > sizeof(buf))
 
187
                return -1;
 
188
 
 
189
        /*
 
190
         * If callback is specified, invoke it, and check its return value.
 
191
         */
 
192
        if(cb) {
 
193
                if(constructed) *buf |= 0x20;
 
194
                if(cb(buf, size, app_key) < 0)
 
195
                        return -1;
 
196
        }
 
197
 
 
198
        return size;
 
199
}