]> git.saurik.com Git - apple/security.git/blob - SecuritySNACCRuntime/c++-lib/src/sm_vdasnacc.cpp
Security-28.tar.gz
[apple/security.git] / SecuritySNACCRuntime / c++-lib / src / sm_vdasnacc.cpp
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 #ifndef __APPLE__
19 #ifndef NO_SCCS_ID
20 static char SccsId[ ] = "@(#) sm_vdasnacc.cpp 1.18 6/1/98 11:07:01";
21 #endif
22 #endif
23
24 /**
25 vdasnacc.CPP
26 This file handles any additional miscellaneous routines to support
27 the integration of the MSP into SNACC environment.
28 ***/
29
30 //#include "sm_api.h"
31 #include "sm_vdasnacc.h"
32 #include "sm_vdatypes.h"
33
34 long vdasnacc_sortSetTag(
35 CSM_Buffer *pEncBuf[], // IN/OUT, buffer to sort
36 int start_index, // IN, start index for sort.
37 int icount, // IN, size of array.
38 int tag); // IN, tag to place.
39 long SM_DetermineLengthBuf(AsnBuf &SNACCinputBuf);
40
41
42 /** This function sorts the specified "Str_struct" array in reverse order.
43 This is done for the "Set Of" ASN.1 ordering. The ASN.1 components will
44 be loaded in ascending order; they will be loaded in the reverse order
45 of this array (hence, we load them in descending order).
46 ***/
47 long vdasnacc_sortSetOf(CSM_Buffer **&pEncBuf, int icount)
48 {
49 long status=0;
50 int lessCount;
51 int i,j;
52 int l1,l2;
53 const char *ptr1,*ptr2;
54 CSM_Buffer *tmpEnc;
55
56 for (i=0; i < icount; i++)
57 {
58 for (j=i+1; j < icount; j++) /** always start with present "i". **/
59 {
60 ptr1 = pEncBuf[i]->Access();
61 ptr2 = pEncBuf[j]->Access();
62 l1 = pEncBuf[i]->Length();
63 l2 = pEncBuf[j]->Length();
64 if (l1 < l2)
65 lessCount = l1;
66 else
67 lessCount = l2;
68 if (memcmp(ptr1, ptr2, lessCount) < 0 ||
69 (memcmp(ptr1, ptr2, lessCount) == 0 &&
70 l1 < l2)) /** check if = with more */
71 { /** SWITCH buffers so that greater is first. **/
72 tmpEnc = pEncBuf[i];
73 pEncBuf[i] = pEncBuf[j];
74 pEncBuf[j] = tmpEnc;
75 }
76 }
77
78 }
79
80
81 return(status);
82 }
83
84
85 /** This function sorts the specified "Str_struct" array in reverse order.
86 This is done for the "Set" ASN.1 ordering. The ASN.1 components will
87 be loaded in ascending order; they will be loaded in the reverse order
88 of this array (hence, we load them in descending order). The SET ordering
89 is based on the lower 5 bits of the tag item (guaranteed to be unique
90 based on the ASN.1 definition of a SET). This is based on the ISO rules.
91 ***/
92 #define ASN_UNIVERSAL 0x00
93 #define ASN_APPLICATION 0x40
94 #define ASN_CONTEXT 0x80
95 #define ASN_PRIVATE 0xC0
96 long vdasnacc_sortSet(CSM_Buffer *pEncBuf[], int icount)
97 {
98 long status=0;
99 int tag_count=0;
100 int tag_index=0;
101
102 // This algorithm for Set ordering requires Universal tags first
103 // followed by Application, then Context specific tags.
104 // Each entry in this category is then sorted by the lower 5 bits.
105 // (They are loaded in reverse order for SNACC buffer loads.)
106 tag_count = vdasnacc_sortSetTag(pEncBuf, tag_index, icount,
107 ASN_PRIVATE);
108 tag_index += tag_count; // skip this set of tags, onto the next.
109 tag_count = vdasnacc_sortSetTag(pEncBuf, tag_index, icount,
110 ASN_CONTEXT);
111 tag_index += tag_count; // skip this set of tags, onto the next.
112 tag_count = vdasnacc_sortSetTag(pEncBuf, tag_index, icount,
113 ASN_APPLICATION);
114 tag_index += tag_count;
115 tag_count = vdasnacc_sortSetTag(pEncBuf, tag_index, icount,
116 ASN_UNIVERSAL);
117
118 return(status);
119 }
120
121
122 // vdasnacc_sortSetTag
123 // This routine sorts the specified buffer from the start index to the end
124 // for the specified tag. This entails switching all entries until the
125 // tagged entries are consecutive, then sorting according the lower 5 bits
126 // of the tags within that tag. The number of entries of that tag type
127 // are returned.
128 long vdasnacc_sortSetTag(
129 CSM_Buffer *pEncBuf[], // IN/OUT, buffer to sort
130 int start_index, // IN, start index for sort.
131 int icount, // IN, size of array.
132 int tag) // IN, tag to place.
133 {
134 int i,j;
135 int tag_count=0;
136 CSM_Buffer *tmpEnc;
137 const char *ptri,*ptrj;
138 int mask = 0x1f; /** for SET, not SET OF logic, only sort based on
139 first 5 bits of tag. **/
140 int mask_TAG = 0xc0; /** mask for upper tag bits indicating UNIVERSAL,
141 APPLICATION or CONTEXT ASN.1 Class. **/
142
143 for (i=start_index; i < icount; i++)
144 {
145 ptri = pEncBuf[i]->Access();
146 if (((ptri[0]&mask_TAG)^tag) != 0)
147 {
148 for (j=i+1; (j < icount) && (((ptri[0]&mask_TAG)^tag) != 0); j++)
149 /** always start with present "i". **/
150 {
151 ptrj = pEncBuf[j]->Access();
152 if (((ptri[0]&mask_TAG)^tag) != 0 &&
153 ((ptrj[0]&mask_TAG)^tag) == 0)
154 { /** SWITCH buffers so that greater is first. **/
155 tmpEnc = pEncBuf[i];
156 pEncBuf[i] = pEncBuf[j];
157 pEncBuf[j] = tmpEnc;
158 ptri = pEncBuf[i]->Access();
159 ptrj = pEncBuf[j]->Access();
160 }
161 }
162 }
163 if (((ptri[0]&mask_TAG)^tag) == 0)
164 tag_count++; // COUNT each of this tag type.
165 }
166
167 for (i=start_index; i < tag_count; i++)
168 {
169 for (j=i+1; j < tag_count; j++) /** always start with present "i". **/
170 {
171 ptri = pEncBuf[i]->Access();
172 ptrj = pEncBuf[j]->Access();
173 if ((ptri[0]&mask) < (ptrj[0]&mask))
174 { /** SWITCH buffers so that greater is first. **/
175 tmpEnc = pEncBuf[i];
176 pEncBuf[i] = pEncBuf[j];
177 pEncBuf[j] = tmpEnc;
178 }
179 }
180 }
181 return(tag_count);
182 }
183
184
185 //
186 // SM_WriteToAsnBuf
187 long SM_WriteToAsnBuf(
188 CSM_Buffer &CBuf, // IN,class must be pre-allocated
189 AsnBuf &SNACCoutputBuf)
190 {
191 long status=0;
192 CSM_Buffer *pCBuf=&CBuf;
193
194 status = SM_WriteToAsnBuf(pCBuf, SNACCoutputBuf);
195 return(status);
196 }
197 long SM_WriteToAsnBuf(
198 CSM_Buffer *&pCBuf, // IN,class must be pre-allocated
199 AsnBuf &SNACCoutputBuf)
200 {
201 long status=0;
202 char *ptr;
203 unsigned int jj=0;
204 SM_SIZE_T lRead=1;
205 SM_SIZE_T lOffset;
206
207 pCBuf->Open(SM_FOPEN_READ);
208 for (jj = 0; jj < pCBuf->Length() && lRead > 0; jj += lRead)
209 {
210 if (jj == 0) // first time, only get last X bytes within 4096 block.
211 {
212 lOffset = pCBuf->Length() - (pCBuf->Length() % 4096);
213 }
214 else
215 lOffset -= 4096;
216 pCBuf->Seek(lOffset, 0);
217 ptr = pCBuf->nRead(4096, lRead);
218 SNACCoutputBuf.PutSegRvs(ptr, lRead);
219 }
220 pCBuf->Close();
221 //SNACCoutputBuf.ResetInReadMode();
222 if (lRead != jj)
223 status = 1; // error.
224 return(status);
225 }
226
227 // SM_ReadFromAsnBuf (pre-alloced version)
228 // This function does the same thing as SM_ReadFromAsnBuf but does not
229 // allocate the incoming CSM_Buffer...
230 long SM_ReadFromAsnBuf(
231 AsnBuf &SNACCinputBuf, // IN, input SNACC buffer
232 CSM_Buffer *pCBuf, // OUT, copied data
233 long length, // IN, length of data to read.
234 CSM_Buffer *preLoad) // IN, optional data to be pre-loaded;
235 // (for SNACC support)
236 {
237 char tmpBuf[4096];
238 unsigned int jj, lWritten, lToRead;
239 int tmpLength;
240
241 if (length == INDEFINITE_LEN)
242 {
243 // RWC; Call custom routine to trace the actual unknown ASN data in the
244 // RWC; buffer and determine the actual length of the buffer (this may
245 // RWC; be a recursive call).
246 AsnBuf SNACCinputBuf2 = SNACCinputBuf; // Create new, working copy for
247 // ASN ANY length determination.
248 length = SM_DetermineLengthBuf(SNACCinputBuf2);
249 }
250
251 tmpLength = length;
252 if (preLoad)
253 tmpLength += preLoad->Length();
254 // pCBuf should already be allocated and ready for use...
255 if (pCBuf == NULL)
256 return -1;
257 pCBuf->Open(SM_FOPEN_WRITE);
258 if (preLoad) // load requested data in front of SNACC buf.
259 pCBuf->Write(preLoad->Access(), preLoad->Length());
260 for (jj=0, lWritten=1;
261 jj < (unsigned int)length && lWritten > 0; jj += lWritten)
262 {
263 if (length - jj < 4096) lToRead = length - jj;
264 else lToRead = 4096;
265 lWritten = SNACCinputBuf.CopyOut(&tmpBuf[0], lToRead);
266 if (lWritten)
267 pCBuf->Write(&tmpBuf[0], lWritten);
268 }
269 pCBuf->Close();
270
271 return (length);
272 }
273
274 // SM_ReadFromAsnBuf (allocating version)
275 // NOTE::: IMPORTANT NOT TO RESET CSM_Buffer Write BUFFER.
276 // ALSO, DO NOT RESET THE AsnBuf from SNACC; this function is used
277 // to read data from ANY components in the incomming SNACC message.
278 long SM_ReadFromAsnBuf(CSM_Buffer *&pCBuf, // OUT,copied data.
279 AsnBuf &SNACCinputBuf, // IN, input SNACC buffer
280 long length, // IN, length of data to read.
281 CSM_Buffer *preLoad) // IN, optional data to be pre-loaded;
282 // (for SNACC support)
283 {
284 int tmpLength;
285
286 tmpLength = length;
287 if (preLoad)
288 tmpLength += preLoad->Length();
289 #if defined(macintosh) || defined(__APPLE__)
290 pCBuf = new CSM_Buffer(length == INDEFINITE_LEN ? 0 : preLoad ? tmpLength : length);
291 #else
292 if (SNACCinputBuf.DataLen() > 16384) // RWC; MUST BE FIXED!!!!
293 pCBuf = new CSM_Buffer(tmpnam(NULL), 0);
294 else
295 pCBuf = new CSM_Buffer(0);
296 #endif
297 return (SM_ReadFromAsnBuf(SNACCinputBuf, pCBuf, length, preLoad));
298 }
299
300 //////////////////////////////////////////////////////////////////////////
301 // SM_AsnBits2Buffer gets the bits out of the snacc AsnBits class and
302 // stores them in a buffer LSB style.
303 long SM_AsnBits2Buffer(AsnBits *pBits, CSM_Buffer *pBuffer)
304 {
305 size_t lBits;
306 size_t lNumBytes;
307 size_t i, j;
308 char *pch;
309 long lRetVal = -1;
310
311 while (true)
312 {
313 if ((pBits == NULL) || (pBuffer == NULL))
314 break;
315
316 lBits = pBits->BitLen();
317 // calculate the number of bytes being put into the buffer
318 lNumBytes = lBits / 8;
319 if (lBits % 8 > 0)
320 lNumBytes++;
321
322 if ((pch = pBuffer->Alloc(lNumBytes)) == NULL)
323 break;
324
325 for (i = 0; i < lNumBytes; i++)
326 {
327 for (j = 0; j < 8 && ((i*8)+j) < lBits; j++)
328 {
329 pch[i] += (pBits->GetBit((i*8)+j) << j);
330 }
331 }
332
333 pBuffer->Open(SM_FOPEN_WRITE);
334 pBuffer->Flush();
335 pBuffer->Close();
336
337 lRetVal = 0;
338 break;
339 }
340 return lRetVal;
341 }
342
343 //////////////////////////////////////////////////////////////////////////
344 // SM_Buffer2AsnBits gets the bits out of the snacc AsnBits class and
345 // stores them in a buffer LSB style.
346 long SM_Buffer2AsnBits(CSM_Buffer *pBuffer, AsnBits *pBits, size_t lBits)
347 {
348 size_t lNumBytes;
349 size_t i, j;
350 const char *pch;
351 long lRetVal = -1;
352
353 if ((pBits != NULL) && (pBuffer != NULL))
354 {
355
356 pBits->ReSet(lBits);
357 // calculate the number of bytes being put into the buffer
358 lNumBytes = lBits / 8;
359 if (lBits % 8 > 0)
360 lNumBytes++;
361 pch = pBuffer->Access();
362
363 for (i = 0; i < lNumBytes; i++)
364 {
365 for (j = 0; j < 8 && ((i*8)+j) < lBits; j++)
366 {
367 if ((pch[i] >> j) & 0x01)
368 pBits->SetBit((i*8)+j);
369 }
370 }
371 lRetVal = 0;
372 }
373
374 return lRetVal;
375 }
376
377 long SM_BufferReverseBits(CSM_Buffer *pBuffer)
378 {
379 long status=0;
380 size_t i;
381 unsigned char *ptr;
382 #ifdef __APPLE__
383 static const short bbb[256]=
384 #else
385 static short bbb[256]=
386 #endif
387 { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
388 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
389 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
390 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
391 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
392 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
393 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
394 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
395 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
396 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
397 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
398 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
399 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
400 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
401 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
402 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
403 };
404
405 if (pBuffer)
406 {
407 ptr = (unsigned char *)pBuffer->Access();
408 for (i=0; i < pBuffer->Length(); i++)
409 {
410 ptr[i] = (char)bbb[ptr[i]];
411 }
412 }
413
414 return(status);
415 }
416
417 #if SM_BUF_2_BIG_INT_STR
418
419 long SM_Buffer2BigIntegerStr( CSM_Buffer *asn1Data,
420 BigIntegerStr &pSnaccBigIntStr,
421 bool unsignedFlag)
422 {
423 BigIntegerStr *p = &pSnaccBigIntStr;
424
425 return(SM_Buffer2BigIntegerStr(asn1Data, p, unsignedFlag));
426 }
427
428 // FUNCTION: SM_Buffer2BigIntegerStr()
429 //
430 // PURPOSE: Encforce ASN.1 encoding rules on the asn1Data. Make sure it's
431 // unsigned if the unsignedFlag is set to true.
432 //
433 long SM_Buffer2BigIntegerStr( CSM_Buffer *asn1Data,
434 BigIntegerStr *&ppSnaccBigIntStr,
435 bool unsignedFlag )
436 {
437 char *pDataCopy = const_cast<char*>(asn1Data->Access());
438 SM_SIZE_T dataLen = asn1Data->Length();
439
440 // UPDATE comment
441
442 /* IF the Fortezza Card generates an r,s,p,q,g or y value in which the
443 * first 9 bits are all set to 0, then the encoding software deletes the
444 * first octet from the octets to be encoded. This rule is applied
445 * repeatedly to the remaining octets until the first 9 bits are not all
446 * set to 0.
447 */
448 if (unsignedFlag == 1)
449 {
450 while ( !( (pDataCopy[0] & 0xFF) || (pDataCopy[1] & 0x80)) )
451 {
452 memcpy( &pDataCopy[0], &pDataCopy[1], (dataLen - 1));
453 dataLen --;
454 pDataCopy[dataLen] = 0;
455 }
456
457 /* If the Fortezza Card generates a r,s,p,q,g, or y value in which the
458 * MSB is set to 1, THEN the software prepends a single octet in which
459 * all bits are set to 0.
460 */
461 if (pDataCopy[0] & 0x80)
462 {
463 char *tmp = NULL;
464
465 tmp = (char *) calloc(1, dataLen + 1);
466
467 tmp[0] = 0;
468 memcpy(&tmp[1], pDataCopy, dataLen);
469 free(pDataCopy);
470 pDataCopy = &tmp[0];
471 dataLen ++;
472
473 }
474 }
475 /*
476 * ASN.1 rules state that the first 9 bits of an integer encoding can
477 * not be all ones or all zeros.
478 */
479 else
480 {
481 /* check for first first 9 bits all ones
482 */
483 while ( (pDataCopy[0] & 0xFF) && (pDataCopy[1] & 0x80) )
484 {
485 memcpy( &pDataCopy[0], &pDataCopy[1], dataLen - 1);
486 dataLen --;
487 pDataCopy[dataLen] = 0;
488 }
489
490 /* check for first 9 bits all zeros
491 */
492 while (pDataCopy[0] == 0 && (pDataCopy[1] >> 7) == 0)
493 {
494 memcpy( &pDataCopy[0], &pDataCopy[1], (dataLen - 1));
495 dataLen --;
496 pDataCopy[dataLen] = 0;
497 }
498 }
499
500 if (ppSnaccBigIntStr == NULL)
501 ppSnaccBigIntStr = new BigIntegerStr( pDataCopy, dataLen);
502 else
503 ppSnaccBigIntStr->ReSet( pDataCopy, dataLen );
504
505 return (0);
506 }
507
508 #endif /* SM_BUF_2_BIG_INT_STR */
509
510 //
511 //
512 // RULES for recursive operation, determining the length of the specified
513 // buffer:
514 // - Always assume only the data from a valid ANY was passed in, missing tag
515 // and length.
516 // - Parse data from the 1st byte; if ASN data sets do not match the specified
517 // length or EOC designator, then we assume it is part of sequence and
518 // continue parsing.
519 //
520 long SM_DetermineLengthBuf(AsnBuf &SNACCinputBuf)
521 {
522 AsnLen length = 0;
523 unsigned long int tagId1;
524 AsnLen elmtLen1;
525 AsnLen elmtLen0=INDEFINITE_LEN;
526 ENV_TYPE env;
527
528 while (elmtLen0 == INDEFINITE_LEN)
529 {
530 tagId1 = BDecTag (SNACCinputBuf, length, env);
531
532 if ((tagId1 == EOC_TAG_ID) && (elmtLen0 == INDEFINITE_LEN))
533 {
534 BDEC_2ND_EOC_OCTET (SNACCinputBuf, length, env);
535 break;
536 }
537 elmtLen1 = BDecLen (SNACCinputBuf, length, env);
538 if (elmtLen1 == INDEFINITE_LEN)
539 {
540 elmtLen1 = SM_DetermineLengthBuf(SNACCinputBuf);
541 length += elmtLen1;
542 }
543 else if (!SNACCinputBuf.ReadError())
544 {
545 SNACCinputBuf.Skip(elmtLen1); // SKIP this ASN.1 component.
546 length += elmtLen1;
547 }
548 else
549 {
550 length = 0;
551 break;
552 }
553 }
554
555 return((long)length);
556
557 }
558
559
560 /*** EOF smimesnacc.CPP ***/