]> git.saurik.com Git - apple/security.git/blob - SecuritySNACCRuntime/c-lib/src/asn-bits.c
Security-54.1.tar.gz
[apple/security.git] / SecuritySNACCRuntime / c-lib / src / asn-bits.c
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 * .../c-lib/src/asn-bits.c - BER encode, decode, print and free routines for ASN.1 BIT STRING type
21 *
22 * MS 92
23 * Copyright (C) 1992 Michael Sample and the University of British Columbia
24 *
25 * This library is free software; you can redistribute it and/or
26 * modify it provided that this copyright/license information is retained
27 * in original form.
28 *
29 * If you modify this file, you must clearly indicate your changes.
30 *
31 * This source code is distributed in the hope that it will be
32 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
33 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
34 *
35 * $Header: /cvs/Darwin/Security/SecuritySNACCRuntime/c-lib/src/asn-bits.c,v 1.1.1.1 2001/05/18 23:14:08 mb Exp $
36 * $Log: asn-bits.c,v $
37 * Revision 1.1.1.1 2001/05/18 23:14:08 mb
38 * Move from private repository to open source repository
39 *
40 * Revision 1.2 2001/05/05 00:59:25 rmurphy
41 * Adding darwin license headers
42 *
43 * Revision 1.1.1.1 1999/03/16 18:06:30 aram
44 * Originals from SMIME Free Library.
45 *
46 * Revision 1.4 1995/07/27 08:57:33 rj
47 * use memcmpeq that is defined in .../snacc.h to use either memcmp or bcmp.
48 *
49 * changed `_' to `-' in file names.
50 *
51 * Revision 1.3 1994/12/11 21:51:31 rj
52 * #include <string(s).h>
53 *
54 * Revision 1.2 1994/08/31 23:56:27 rj
55 * two unused variables removed.
56 *
57 * Revision 1.1 1994/08/28 09:45:50 rj
58 * first check-in. for a list of changes to the snacc-1.1 distribution please refer to the ChangeLog.
59 *
60 */
61
62 #include "asn-config.h"
63
64 #if STDC_HEADERS || HAVE_STRING_H
65 #include <string.h>
66 #else
67 #include <strings.h>
68 #endif
69
70 #include "asn-len.h"
71 #include "asn-tag.h"
72 #include "str-stk.h"
73 #include "asn-bits.h"
74
75 static unsigned short int unusedBitsG;
76
77 char numToHexCharTblG[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
78
79
80
81 /*
82 * encodes universal TAG LENGTH and Contents of and ASN.1 BIT STRING
83 */
84 AsnLen
85 BEncAsnBits PARAMS ((b, data),
86 BUF_TYPE b _AND_
87 AsnBits *data)
88 {
89 AsnLen len;
90
91 len = BEncAsnBitsContent (b, data);
92 len += BEncDefLen (b, len);
93 len += BEncTag1 (b, UNIV, PRIM, BITSTRING_TAG_CODE);
94 return len;
95 } /* BEncAsnInt */
96
97
98 /*
99 * decodes universal TAG LENGTH and Contents of and ASN.1 BIT STRING
100 */
101 void
102 BDecAsnBits PARAMS ((b, result, bytesDecoded, env),
103 BUF_TYPE b _AND_
104 AsnBits *result _AND_
105 AsnLen *bytesDecoded _AND_
106 jmp_buf env)
107 {
108 AsnTag tag;
109 AsnLen elmtLen;
110
111 if (((tag =BDecTag (b, bytesDecoded, env)) !=
112 MAKE_TAG_ID (UNIV, PRIM, BITSTRING_TAG_CODE)) &&
113 (tag != MAKE_TAG_ID (UNIV, CONS, BITSTRING_TAG_CODE)))
114 {
115 Asn1Error ("BDecAsnBits: ERROR - wrong tag on BIT STRING.\n");
116 longjmp (env, -40);
117 }
118
119 elmtLen = BDecLen (b, bytesDecoded, env);
120 BDecAsnBitsContent (b, tag, elmtLen, result, bytesDecoded, env);
121
122 } /* BDecAsnBits */
123
124
125
126 /*
127 * Encodes the BIT STRING value (including the unused bits
128 * byte) to the given buffer.
129 */
130 AsnLen
131 BEncAsnBitsContent PARAMS ((b, bits),
132 BUF_TYPE b _AND_
133 AsnBits *bits)
134 {
135 unsigned long int unusedBits;
136 unsigned long int byteLen;
137
138 if (bits->bitLen == 0)
139 byteLen = 0;
140 else
141 byteLen = ((bits->bitLen-1) / 8) + 1;
142
143 BufPutSegRvs (b, bits->bits, byteLen);
144 unusedBits = (bits->bitLen % 8);
145 if (unusedBits != 0)
146 unusedBits = 8 - unusedBits;
147 BufPutByteRvs (b, unusedBits);
148 return byteLen + 1;
149
150 } /* BEncAsnBitsContent */
151
152
153 /*
154 * Used when decoding to combine constructed pieces into one
155 * contiguous block.
156 * Fills string stack with references to the pieces of a
157 * construced bit string. sets unusedBitsG appropriately.
158 * and strStkG.totalByteLenG to bytelen needed to hold the bitstring
159 */
160 static void
161 FillBitStringStk PARAMS ((b, elmtLen0, bytesDecoded, env),
162 BUF_TYPE b _AND_
163 AsnLen elmtLen0 _AND_
164 AsnLen *bytesDecoded _AND_
165 jmp_buf env)
166 {
167 unsigned long int refdLen;
168 unsigned long int totalRefdLen;
169 char *strPtr;
170 unsigned long int totalElmtsLen1 = 0;
171 unsigned long int tagId1;
172 unsigned long int elmtLen1;
173 unsigned long int lenToRef;
174
175 for (; (totalElmtsLen1 < elmtLen0) || (elmtLen0 == INDEFINITE_LEN); )
176 {
177 tagId1 = BDecTag (b, &totalElmtsLen1, env);
178
179 if ((tagId1 == EOC_TAG_ID) && (elmtLen0 == INDEFINITE_LEN))
180 {
181 BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1, env);
182 break;
183 }
184
185 elmtLen1 = BDecLen (b, &totalElmtsLen1, env);
186 if (tagId1 == MAKE_TAG_ID (UNIV, PRIM, BITSTRING_TAG_CODE))
187 {
188 /*
189 * primitive part of string, put references to piece (s) in
190 * str stack
191 */
192
193 /*
194 * get unused bits octet
195 */
196 if (unusedBitsG != 0)
197 {
198 /*
199 * whoa - only allowed non-octet aligned bits on
200 * on last piece of bits string
201 */
202 Asn1Error ("FillBitStringStk: ERROR - a component of a constructed BIT STRING that is not the last has non-zero unused bits\n");
203 longjmp (env, -1);
204 }
205
206 if (elmtLen1 != 0)
207 unusedBitsG = BufGetByte (b);
208
209 totalRefdLen = 0;
210 lenToRef =elmtLen1-1; /* remove one octet for the unused bits oct*/
211 refdLen = lenToRef;
212 while (1)
213 {
214 strPtr = BufGetSeg (b, &refdLen);
215
216 PUSH_STR (strPtr, refdLen, env);
217 totalRefdLen += refdLen;
218 if (totalRefdLen == lenToRef)
219 break; /* exit this while loop */
220
221 if (refdLen == 0) /* end of data */
222 {
223 Asn1Error ("FillBitStringStk: ERROR - expecting more data\n");
224 longjmp (env, -2);
225 }
226 refdLen = lenToRef - totalRefdLen;
227 }
228 totalElmtsLen1 += elmtLen1;
229 }
230
231
232 else if (tagId1 == MAKE_TAG_ID (UNIV, CONS, BITSTRING_TAG_CODE))
233 {
234 /*
235 * constructed octets string embedding in this constructed
236 * octet string. decode it.
237 */
238 FillBitStringStk (b, elmtLen1, &totalElmtsLen1, env);
239 }
240 else /* wrong tag */
241 {
242 Asn1Error ("FillBitStringStk: ERROR - decoded non-BIT STRING tag inside a constructed BIT STRING\n");
243 longjmp (env, -3);
244 }
245 } /* end of for */
246
247 (*bytesDecoded) += totalElmtsLen1;
248
249 } /* FillBitStringStk */
250
251
252 /*
253 * Decodes a seq of universally tagged bits until either EOC is
254 * encountered or the given len decoded. Returns them in a
255 * single concatenated bit string
256 */
257 static void
258 BDecConsAsnBits PARAMS ((b, len, result, bytesDecoded, env),
259 BUF_TYPE b _AND_
260 AsnLen len _AND_
261 AsnBits *result _AND_
262 AsnLen *bytesDecoded _AND_
263 jmp_buf env)
264 {
265 char *bufCurr;
266 unsigned long int curr;
267
268 RESET_STR_STK();
269
270 /*
271 * decode each piece of the octet string, puting
272 * an entry in the octet/bit string stack for each
273 */
274 FillBitStringStk (b, len, bytesDecoded, env);
275
276 /* alloc single str long enough for combined bitstring */
277 result->bitLen = strStkG.totalByteLen*8 - unusedBitsG;
278
279 bufCurr = result->bits = Asn1Alloc (strStkG.totalByteLen);
280
281 /* copy bit string pieces (buffer refs) into single block */
282 for (curr = 0; curr < strStkG.nextFreeElmt; curr++)
283 {
284 memcpy (bufCurr, strStkG.stk[curr].str, strStkG.stk[curr].len);
285 bufCurr += strStkG.stk[curr].len;
286 }
287
288 } /* BDecConsAsnBits */
289
290 /*
291 * Decodes the content of a BIT STRING (including the unused bits octet)
292 * Always returns a single contiguous bit string
293 */
294 void
295 BDecAsnBitsContent PARAMS ((b, tagId, len, result, bytesDecoded, env),
296 BUF_TYPE b _AND_
297 AsnTag tagId _AND_
298 AsnLen len _AND_
299 AsnBits *result _AND_
300 AsnLen *bytesDecoded _AND_
301 jmp_buf env)
302 {
303 /*
304 * tagId is encoded tag shifted into long int.
305 * if CONS bit is set then constructed bit string
306 */
307 if (TAG_IS_CONS (tagId))
308 BDecConsAsnBits (b, len, result, bytesDecoded, env);
309 else /* primitive octet string */
310 {
311 (*bytesDecoded) += len;
312 len--;
313 result->bitLen = (len * 8) - (unsigned int)BufGetByte (b);
314 result->bits = Asn1Alloc (len);
315 BufCopy (result->bits, b, len);
316 if (BufReadError (b))
317 {
318 Asn1Error ("BDecAsnBitsContent: ERROR - decoded past end of data\n");
319 longjmp (env, -4);
320 }
321 }
322 } /* BDecAsnBitsContent */
323
324
325
326 /*
327 * Frees the string part of a BIT STRING
328 */
329 void
330 FreeAsnBits PARAMS ((v),
331 AsnBits *v)
332 {
333 Asn1Free (v->bits);
334 } /* FreeAsnBits */
335
336
337 /*
338 * Prints the contents of the given BIT STRING to the
339 * given file. indent is ignored. Always uses ASN.1 Value Notaion
340 * Hex format. (Should be binary versions in some cases)
341 */
342 void
343 PrintAsnBits PARAMS ((f,v, indent),
344 FILE *f _AND_
345 AsnBits *v _AND_
346 unsigned short indent)
347 {
348 int i;
349 unsigned long int octetLen;
350
351 if (v->bitLen == 0)
352 octetLen = 0;
353 else
354 octetLen = (v->bitLen-1)/8 +1;
355
356 fprintf (f,"'");
357 for (i = 0; i < octetLen; i++)
358 fprintf (f,"%c%c", TO_HEX (v->bits[i] >> 4), TO_HEX (v->bits[i]));
359 fprintf (f,"'H");
360
361 } /* PrintAsnBits */
362
363 /*
364 * Returns TRUE if the given BIT STRINGs are identical.
365 * Otherwise returns FALSE.
366 */
367 int
368 AsnBitsEquiv PARAMS ((b1, b2),
369 AsnBits *b1 _AND_
370 AsnBits *b2)
371 {
372 int octetsLessOne;
373 int octetBits;
374
375 if ((b1->bitLen == 0) && (b2->bitLen == 0))
376 return TRUE;
377
378 octetsLessOne = (b1->bitLen-1)/8;
379 octetBits = 7 - (b1->bitLen % 8);
380
381 /* trailing bits may not be significant */
382 return b1->bitLen == b2->bitLen && !memcmpeq (b1->bits, b2->bits, octetsLessOne) && ((b1->bits[octetsLessOne] & (0xFF << octetBits)) == (b1->bits[octetsLessOne] & (0xFF << octetBits)));
383
384 } /* AsnBitsEquiv */
385
386
387 /*
388 * Set given bit to 1. Most significant bit is bit 0, least significant
389 * is bit (v1->bitLen -1)
390 */
391 void
392 SetAsnBit PARAMS ((b1, bit),
393 AsnBits *b1 _AND_
394 unsigned long int bit)
395 {
396 unsigned long int octet;
397 unsigned long int octetsBit;
398
399 if (bit < b1->bitLen)
400 {
401 octet = bit/8;
402 octetsBit = 7 - (bit % 8);/* bit zero is first/most sig bit in octet */
403 b1->bits[octet] |= 1 << octetsBit;
404 }
405 } /* SetAsnBit */
406
407
408 /*
409 * Set given bit to 0. Most significant bit is bit 0, least significant
410 * is bit (v1->bitLen -1)
411 */
412 void
413 ClrAsnBit PARAMS ((b1, bit),
414 AsnBits *b1 _AND_
415 unsigned long int bit)
416 {
417 unsigned long int octet;
418 unsigned long int octetsBit;
419
420 if (bit < b1->bitLen)
421 {
422 octet = bit/8;
423 octetsBit = 7 - (bit % 8);/* bit zero is first/most sig bit in octet */
424 b1->bits[octet] &= ~(1 << octetsBit);
425 }
426
427 } /* ClrAsnBit */
428
429
430 /*
431 * Get given bit. Most significant bit is bit 0, least significant
432 * is bit (v1->bitLen -1). Returns TRUE if the bit is 1. Returns FALSE
433 * if the bit is 0. if the bit is out of range then returns 0.
434 */
435 int
436 GetAsnBit PARAMS ((b1, bit),
437 AsnBits *b1 _AND_
438 unsigned long int bit)
439 {
440 unsigned long int octet;
441 unsigned long int octetsBit;
442
443 if (bit < b1->bitLen)
444 {
445 octet = bit/8;
446 octetsBit = 7 - (bit % 8); /* bit zero is first/most sig bit in octet*/
447 return b1->bits[octet] & (1 << octetsBit);
448 }
449 return 0;
450 } /* AsnBits::GetBit */