Branch data Line data Source code
1 : : /* asn1.c --- Wrapper around pseudo-ASN.1 token format.
2 : : * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Simon Josefsson
3 : : *
4 : : * This file is part of the Generic Security Service (GSS).
5 : : *
6 : : * GSS is free software; you can redistribute it and/or modify it
7 : : * under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 3 of the License, or
9 : : * (at your option) any later version.
10 : : *
11 : : * GSS is distributed in the hope that it will be useful, but WITHOUT
12 : : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 : : * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 : : * License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with GSS; if not, see http://www.gnu.org/licenses or write to
18 : : * the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19 : : * Floor, Boston, MA 02110-1301, USA.
20 : : *
21 : : */
22 : :
23 : : #include "internal.h"
24 : :
25 : : /*
26 : : * The following two functions borrowed from libtasn.1, under LGPL.
27 : : * Copyright (C) 2002 Fabio Fiorina.
28 : : */
29 : : static void
30 : 40 : _gss_asn1_length_der (size_t len, unsigned char *ans, size_t * ans_len)
31 : : {
32 : : size_t k;
33 : : unsigned char temp[sizeof (len)];
34 : :
35 [ + + ]: 40 : if (len < 128)
36 : : {
37 [ + + ]: 34 : if (ans != NULL)
38 : 17 : ans[0] = (unsigned char) len;
39 : 34 : *ans_len = 1;
40 : : }
41 : : else
42 : : {
43 : 6 : k = 0;
44 : :
45 [ + + ]: 18 : while (len)
46 : : {
47 : 12 : temp[k++] = len & 0xFF;
48 : 12 : len = len >> 8;
49 : : }
50 : :
51 : 6 : *ans_len = k + 1;
52 : :
53 [ + + ]: 6 : if (ans != NULL)
54 : : {
55 : 3 : ans[0] = ((unsigned char) k & 0x7F) + 128;
56 [ + + ]: 9 : while (k--)
57 : 6 : ans[*ans_len - 1 - k] = temp[k];
58 : : }
59 : : }
60 : 40 : }
61 : :
62 : : static size_t
63 : 22 : _gss_asn1_get_length_der (const char *der, size_t der_len, size_t * len)
64 : : {
65 : : size_t ans;
66 : : size_t k, punt;
67 : :
68 : 22 : *len = 0;
69 [ - + ]: 22 : if (der_len <= 0)
70 : 0 : return 0;
71 : :
72 [ + + ]: 22 : if (!(der[0] & 128))
73 : : {
74 : : /* short form */
75 : 19 : *len = 1;
76 : 19 : return (unsigned char) der[0];
77 : : }
78 : : else
79 : : {
80 : : /* Long form */
81 : 3 : k = (unsigned char) der[0] & 0x7F;
82 : 3 : punt = 1;
83 [ + - ]: 3 : if (k)
84 : : { /* definite length method */
85 : 3 : ans = 0;
86 [ + + ][ + - ]: 9 : while (punt <= k && punt < der_len)
87 : : {
88 : 6 : size_t last = ans;
89 : :
90 : 6 : ans = ans * 256 + (unsigned char) der[punt++];
91 [ - + ]: 6 : if (ans < last)
92 : : /* we wrapped around, no bignum support... */
93 : 0 : return -2;
94 : : }
95 : : }
96 : : else
97 : : { /* indefinite length method */
98 : 0 : ans = -1;
99 : : }
100 : :
101 : 3 : *len = punt;
102 : 22 : return ans;
103 : : }
104 : : }
105 : :
106 : : OM_uint32
107 : 10 : _gss_encapsulate_token_prefix (const char *prefix, size_t prefixlen,
108 : : const char *in, size_t inlen,
109 : : const char *oid, OM_uint32 oidlen,
110 : : void **out, size_t * outlen)
111 : : {
112 : : size_t oidlenlen;
113 : : size_t asn1len, asn1lenlen;
114 : : unsigned char *p;
115 : :
116 [ + + ]: 10 : if (prefix == NULL)
117 : 4 : prefixlen = 0;
118 : :
119 : 10 : _gss_asn1_length_der (oidlen, NULL, &oidlenlen);
120 : 10 : asn1len = 1 + oidlenlen + oidlen + prefixlen + inlen;
121 : 10 : _gss_asn1_length_der (asn1len, NULL, &asn1lenlen);
122 : :
123 : 10 : *outlen = 1 + asn1lenlen + asn1len;
124 : 10 : p = *out = malloc (*outlen);
125 [ - + ]: 10 : if (!p)
126 : 0 : return -1;
127 : :
128 : 10 : *p++ = '\x60';
129 : 10 : _gss_asn1_length_der (asn1len, p, &asn1lenlen);
130 : 10 : p += asn1lenlen;
131 : 10 : *p++ = '\x06';
132 : 10 : _gss_asn1_length_der (oidlen, p, &oidlenlen);
133 : 10 : p += oidlenlen;
134 : 10 : memcpy (p, oid, oidlen);
135 : 10 : p += oidlen;
136 [ + + ]: 10 : if (prefixlen > 0)
137 : : {
138 : 6 : memcpy (p, prefix, prefixlen);
139 : 6 : p += prefixlen;
140 : : }
141 : 10 : memcpy (p, in, inlen);
142 : :
143 : 10 : return 0;
144 : : }
145 : :
146 : : /**
147 : : * gss_encapsulate_token:
148 : : * @input_token: (buffer, opaque, read) Buffer with GSS-API context token data.
149 : : * @token_oid: (Object ID, read) Object identifier of token.
150 : : * @output_token: (buffer, opaque, modify) Encapsulated token data;
151 : : * caller must release with gss_release_buffer().
152 : : *
153 : : * Add the mechanism-independent token header to GSS-API context token
154 : : * data.
155 : : *
156 : : * Returns:
157 : : *
158 : : * `GSS_S_COMPLETE`: Indicates successful completion, and that output
159 : : * parameters holds correct information.
160 : : *
161 : : * `GSS_S_FAILURE`: Indicates that encapsulation failed for reasons
162 : : * unspecified at the GSS-API level.
163 : : **/
164 : : extern OM_uint32
165 : 4 : gss_encapsulate_token (const gss_buffer_t input_token,
166 : : const gss_OID token_oid, gss_buffer_t output_token)
167 : : {
168 : : int rc;
169 : :
170 [ - + ]: 4 : if (!input_token)
171 : 0 : return GSS_S_CALL_INACCESSIBLE_READ;
172 [ - + ]: 4 : if (!token_oid)
173 : 0 : return GSS_S_CALL_INACCESSIBLE_READ;
174 [ - + ]: 4 : if (!output_token)
175 : 0 : return GSS_S_CALL_INACCESSIBLE_WRITE;
176 : :
177 : 4 : rc = _gss_encapsulate_token_prefix (NULL, 0,
178 : 4 : input_token->value,
179 : : input_token->length,
180 : 4 : token_oid->elements,
181 : : token_oid->length,
182 : : &output_token->value,
183 : : &output_token->length);
184 [ - + ]: 4 : if (rc != 0)
185 : 0 : return GSS_S_FAILURE;
186 : :
187 : 4 : return GSS_S_COMPLETE;
188 : : }
189 : :
190 : : static int
191 : 11 : _gss_decapsulate_token (const char *in, size_t inlen,
192 : : char **oid, size_t * oidlen,
193 : : char **out, size_t * outlen)
194 : : {
195 : : size_t i;
196 : : size_t asn1lenlen;
197 : :
198 [ - + ]: 11 : if (inlen-- == 0)
199 : 0 : return -1;
200 [ - + ]: 11 : if (*in++ != '\x60')
201 : 0 : return -1;
202 : :
203 : 11 : i = inlen;
204 : 11 : asn1lenlen = _gss_asn1_get_length_der (in, inlen, &i);
205 [ - + ]: 11 : if (inlen < i)
206 : 0 : return -1;
207 : :
208 : 11 : inlen -= i;
209 : 11 : in += i;
210 : :
211 [ - + ]: 11 : if (inlen != asn1lenlen)
212 : 0 : return -1;
213 : :
214 [ - + ]: 11 : if (inlen-- == 0)
215 : 0 : return -1;
216 [ - + ]: 11 : if (*in++ != '\x06')
217 : 0 : return -1;
218 : :
219 : 11 : i = inlen;
220 : 11 : asn1lenlen = _gss_asn1_get_length_der (in, inlen, &i);
221 [ - + ]: 11 : if (inlen < i)
222 : 0 : return -1;
223 : :
224 : 11 : inlen -= i;
225 : 11 : in += i;
226 : :
227 [ + + ]: 11 : if (inlen < asn1lenlen)
228 : 1 : return -1;
229 : :
230 : 10 : *oidlen = asn1lenlen;
231 : 10 : *oid = (char *) in;
232 : :
233 : 10 : inlen -= asn1lenlen;
234 : 10 : in += asn1lenlen;
235 : :
236 : 10 : *outlen = inlen;
237 : 10 : *out = (char *) in;
238 : :
239 : 11 : return 0;
240 : : }
241 : :
242 : : /**
243 : : * gss_decapsulate_token:
244 : : * @input_token: (buffer, opaque, read) Buffer with GSS-API context token.
245 : : * @token_oid: (Object ID, read) Expected object identifier of token.
246 : : * @output_token: (buffer, opaque, modify) Decapsulated token data;
247 : : * caller must release with gss_release_buffer().
248 : : *
249 : : * Remove the mechanism-independent token header from an initial
250 : : * GSS-API context token.
251 : : *
252 : : * Return value:
253 : : *
254 : : * `GSS_S_COMPLETE`: Indicates successful completion, and that output
255 : : * parameters holds correct information.
256 : : *
257 : : * `GSS_S_DEFECTIVE_TOKEN`: Means that the token failed consistency
258 : : * checks (e.g., OID mismatch or ASN.1 DER length errors).
259 : : *
260 : : * `GSS_S_FAILURE`: Indicates that decapsulation failed for reasons
261 : : * unspecified at the GSS-API level.
262 : : **/
263 : : OM_uint32
264 : 11 : gss_decapsulate_token (const gss_buffer_t input_token,
265 : : const gss_OID token_oid, gss_buffer_t output_token)
266 : : {
267 : : gss_OID_desc tmpoid;
268 : 11 : char *oid = NULL, *out = NULL;
269 : 11 : size_t oidlen = 0, outlen = 0;
270 : :
271 [ - + ]: 11 : if (!input_token)
272 : 0 : return GSS_S_CALL_INACCESSIBLE_READ;
273 [ - + ]: 11 : if (!token_oid)
274 : 0 : return GSS_S_CALL_INACCESSIBLE_READ;
275 [ - + ]: 11 : if (!output_token)
276 : 0 : return GSS_S_CALL_INACCESSIBLE_WRITE;
277 : :
278 [ + + ]: 11 : if (_gss_decapsulate_token ((char *) input_token->value,
279 : : input_token->length,
280 : : &oid, &oidlen, &out, &outlen) != 0)
281 : 1 : return GSS_S_DEFECTIVE_TOKEN;
282 : :
283 : 10 : tmpoid.length = oidlen;
284 : 10 : tmpoid.elements = oid;
285 : :
286 [ + + ]: 10 : if (!gss_oid_equal (token_oid, &tmpoid))
287 : 1 : return GSS_S_DEFECTIVE_TOKEN;
288 : :
289 : 9 : output_token->length = outlen;
290 : 9 : output_token->value = malloc (outlen);
291 [ - + ]: 9 : if (!output_token->value)
292 : 0 : return GSS_S_FAILURE;
293 : :
294 : 9 : memcpy (output_token->value, out, outlen);
295 : :
296 : 11 : return GSS_S_COMPLETE;
297 : : }
|