1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 /*
5  * pkix_pl_bytearray.c
6  *
7  * ByteArray Object Functions
8  *
9  */
10 
11 #include "pkix_pl_bytearray.h"
12 
13 /* --Private-ByteArray-Functions------------------------------------- */
14 
15 /*
16  * FUNCTION: pkix_pl_ByteArray_ToHexString
17  * DESCRIPTION:
18  *
19  *  Creates a hex-String representation of the ByteArray pointed to by "array"
20  *  and stores the result at "pString". The hex-String consists of hex-digit
21  *  pairs separated by spaces, and the entire string enclosed within square
22  *  brackets, e.g. [43 61 6E 20 79 6F 75 20 72 65 61 64 20 74 68 69 73 3F].
23  *  A zero-length ByteArray is represented as [].
24  * PARAMETERS
25  *  "array"
26  *      ByteArray to be represented by the hex-String; must be non-NULL
27  *  "pString"
28  *      Address where String will be stored. Must be non-NULL.
29  *  "plContext"
30  *      Platform-specific context pointer.
31  * THREAD SAFETY:
32  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
33  * RETURNS:
34  *  Returns NULL if the function succeeds.
35  *  Returns a Cert Error if the function fails in a non-fatal way.
36  *  Returns a Fatal Error if the function fails in an unrecoverable way.
37  */
38 PKIX_Error *
pkix_pl_ByteArray_ToHexString(PKIX_PL_ByteArray * array,PKIX_PL_String ** pString,void * plContext)39 pkix_pl_ByteArray_ToHexString(
40         PKIX_PL_ByteArray *array,
41         PKIX_PL_String **pString,
42         void *plContext)
43 {
44         char *tempText = NULL;
45         char *stringText = NULL; /* "[XX XX XX ...]" */
46         PKIX_UInt32 i, outputLen, bufferSize;
47 
48         PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_ToHexString");
49         PKIX_NULLCHECK_TWO(array, pString);
50 
51         if ((array->length) == 0) {
52                 PKIX_CHECK(PKIX_PL_String_Create
53                         (PKIX_ESCASCII, "[]", 0, pString, plContext),
54                         PKIX_COULDNOTCREATESTRING);
55         } else {
56                 /*
57                  * Allocate space for format string
58                  * '[' + "XX" + (n-1)*" XX" + ']' + '\0'
59                  */
60                 bufferSize = 2 + (3*(array->length));
61 
62                 PKIX_CHECK(PKIX_PL_Malloc
63                         (bufferSize, (void **)&stringText, plContext),
64                         PKIX_COULDNOTALLOCATEMEMORY);
65 
66                 stringText[0] = 0;
67                 outputLen = 0;
68 
69                 PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n");
70                 tempText = PR_smprintf
71                         ("[%02X", (0x0FF&((char *)(array->array))[0]));
72                 PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n");
73                 outputLen += PL_strlen(tempText);
74 
75                 PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n");
76                 stringText = PL_strcat(stringText, tempText);
77 
78                 PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n");
79                 PR_smprintf_free(tempText);
80 
81                 for (i = 1; i < array->length; i++) {
82                         PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n");
83                         tempText = PR_smprintf
84                                 (" %02X", (0x0FF&((char *)(array->array))[i]));
85 
86                         if (tempText == NULL){
87                                 PKIX_ERROR(PKIX_PRSMPRINTFFAILED);
88                         }
89 
90                         PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n");
91                         outputLen += PL_strlen(tempText);
92 
93                         PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n");
94                         stringText = PL_strcat(stringText, tempText);
95 
96                         PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n");
97                         PR_smprintf_free(tempText);
98                         tempText = NULL;
99                 }
100 
101                 stringText[outputLen++] = ']';
102                 stringText[outputLen] = 0;
103 
104                 PKIX_CHECK(PKIX_PL_String_Create
105                         (PKIX_ESCASCII,
106                         stringText,
107                         0,
108                         pString,
109                         plContext),
110                         PKIX_COULDNOTCREATESTRING);
111         }
112 
113 cleanup:
114 
115         PKIX_FREE(stringText);
116         PKIX_RETURN(BYTEARRAY);
117 }
118 
119 /*
120  * FUNCTION: pkix_pl_ByteArray_Comparator
121  * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h)
122  *
123  *  NOTE:
124  *  It is not clear that this definition of comparing byte arrays makes
125  *  sense. It does allow you to tell whether two blocks of memory are
126  *  identical, so we only use it for the Equals function (i.e. we don't
127  *  register it as a Compare function for ByteArray).
128  */
129 static PKIX_Error *
pkix_pl_ByteArray_Comparator(PKIX_PL_Object * firstObject,PKIX_PL_Object * secondObject,PKIX_Int32 * pResult,void * plContext)130 pkix_pl_ByteArray_Comparator(
131         PKIX_PL_Object *firstObject,
132         PKIX_PL_Object *secondObject,
133         PKIX_Int32 *pResult,
134         void *plContext)
135 {
136         PKIX_PL_ByteArray *firstByteArray = NULL;
137         PKIX_PL_ByteArray *secondByteArray = NULL;
138         unsigned char *firstData = NULL;
139         unsigned char *secondData = NULL;
140         PKIX_UInt32 i;
141 
142         PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Comparator");
143         PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
144 
145         PKIX_CHECK(pkix_CheckTypes
146                 (firstObject, secondObject, PKIX_BYTEARRAY_TYPE, plContext),
147                 PKIX_ARGUMENTSNOTBYTEARRAYS);
148 
149         /* It's safe to cast */
150         firstByteArray = (PKIX_PL_ByteArray *)firstObject;
151         secondByteArray = (PKIX_PL_ByteArray *)secondObject;
152 
153         *pResult = 0;
154         firstData = (unsigned char *)firstByteArray->array;
155         secondData = (unsigned char *)secondByteArray->array;
156 
157         if (firstByteArray->length < secondByteArray->length) {
158                 *pResult = -1;
159         } else if (firstByteArray->length > secondByteArray->length) {
160                 *pResult = 1;
161         } else if (firstByteArray->length == secondByteArray->length) {
162                 /* Check if both array contents are identical */
163                 for (i = 0;
164                     (i < firstByteArray->length) && (*pResult == 0);
165                     i++) {
166                         if (firstData[i] < secondData[i]) {
167                                 *pResult = -1;
168                         } else if (firstData[i] > secondData[i]) {
169                                 *pResult = 1;
170                         }
171                 }
172         }
173 
174 cleanup:
175 
176         PKIX_RETURN(BYTEARRAY);
177 }
178 
179 /*
180  * FUNCTION: pkix_pl_ByteArray_ToString
181  * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
182  */
183 static PKIX_Error *
pkix_pl_ByteArray_ToString(PKIX_PL_Object * object,PKIX_PL_String ** pString,void * plContext)184 pkix_pl_ByteArray_ToString(
185         PKIX_PL_Object *object,
186         PKIX_PL_String **pString,
187         void *plContext)
188 {
189         PKIX_PL_ByteArray *array = NULL;
190         char *tempText = NULL;
191         char *stringText = NULL; /* "[OOO, OOO, ... OOO]" */
192         PKIX_UInt32 i, outputLen, bufferSize;
193 
194         PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_ToString");
195         PKIX_NULLCHECK_TWO(object, pString);
196 
197         PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext),
198                     PKIX_OBJECTNOTBYTEARRAY);
199 
200         array = (PKIX_PL_ByteArray *)object;
201 
202         if ((array->length) == 0) {
203                 PKIX_CHECK(PKIX_PL_String_Create
204                         (PKIX_ESCASCII, "[]", 0, pString, plContext),
205                         PKIX_COULDNOTCREATESTRING);
206         } else {
207                 /* Allocate space for "XXX, ". */
208                 bufferSize = 2+5*array->length;
209 
210                 /* Allocate space for format string */
211                 PKIX_CHECK(PKIX_PL_Malloc
212                         (bufferSize, (void **)&stringText, plContext),
213                         PKIX_MALLOCFAILED);
214 
215                 stringText[0] = 0;
216                 outputLen = 0;
217 
218                 PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n");
219                 tempText =
220                         PR_smprintf
221                             ("[%03u", (0x0FF&((char *)(array->array))[0]));
222                 PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n");
223                 outputLen += PL_strlen(tempText);
224 
225                 PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n");
226                 stringText = PL_strcat(stringText, tempText);
227 
228                 PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n");
229                 PR_smprintf_free(tempText);
230 
231                 for (i = 1; i < array->length; i++) {
232                         PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n");
233                         tempText = PR_smprintf
234                                 (", %03u",
235                                 (0x0FF&((char *)(array->array))[i]));
236 
237                         if (tempText == NULL){
238                                 PKIX_ERROR(PKIX_PRSMPRINTFFAILED);
239                         }
240 
241                         PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n");
242                         outputLen += PL_strlen(tempText);
243 
244                         PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n");
245                         stringText = PL_strcat(stringText, tempText);
246 
247                         PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n");
248                         PR_smprintf_free(tempText);
249                         tempText = NULL;
250                 }
251 
252                 stringText[outputLen++] = ']';
253                 stringText[outputLen] = 0;
254 
255                 PKIX_CHECK(PKIX_PL_String_Create
256                         (PKIX_ESCASCII, stringText, 0, pString, plContext),
257                         PKIX_STRINGCREATEFAILED);
258 
259         }
260 
261 cleanup:
262 
263         PKIX_FREE(stringText);
264         PKIX_RETURN(BYTEARRAY);
265 }
266 
267 /*
268  * FUNCTION: pkix_pl_ByteArray_Equals
269  * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
270  */
271 static PKIX_Error *
pkix_pl_ByteArray_Equals(PKIX_PL_Object * first,PKIX_PL_Object * second,PKIX_Boolean * pResult,void * plContext)272 pkix_pl_ByteArray_Equals(
273         PKIX_PL_Object *first,
274         PKIX_PL_Object *second,
275         PKIX_Boolean *pResult,
276         void *plContext)
277 {
278         PKIX_UInt32 secondType;
279         PKIX_Int32 cmpResult = 0;
280 
281         PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Equals");
282         PKIX_NULLCHECK_THREE(first, second, pResult);
283 
284         /* Sanity check: Test that "first" is a ByteArray */
285         PKIX_CHECK(pkix_CheckType(first, PKIX_BYTEARRAY_TYPE, plContext),
286                     PKIX_FIRSTARGUMENTNOTBYTEARRAY);
287 
288         PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext),
289                     PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
290 
291         /* If types differ, then we will return false */
292         *pResult = PKIX_FALSE;
293 
294         /* Second type may not be a BA */
295         if (secondType != PKIX_BYTEARRAY_TYPE) goto cleanup;
296 
297         /* It's safe to cast here */
298         PKIX_CHECK(pkix_pl_ByteArray_Comparator
299                 (first, second, &cmpResult, plContext),
300                 PKIX_BYTEARRAYCOMPARATORFAILED);
301 
302         /* ByteArrays are equal iff Comparator Result is 0 */
303         *pResult = (cmpResult == 0);
304 
305 cleanup:
306 
307         PKIX_RETURN(BYTEARRAY);
308 }
309 
310 /*
311  * FUNCTION: pkix_pl_ByteArray_Destroy
312  * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
313  */
314 static PKIX_Error *
pkix_pl_ByteArray_Destroy(PKIX_PL_Object * object,void * plContext)315 pkix_pl_ByteArray_Destroy(
316         PKIX_PL_Object *object,
317         void *plContext)
318 {
319         PKIX_PL_ByteArray *array = NULL;
320 
321         PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Destroy");
322         PKIX_NULLCHECK_ONE(object);
323 
324         PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext),
325                     PKIX_OBJECTNOTBYTEARRAY);
326 
327         array = (PKIX_PL_ByteArray*)object;
328 
329         PKIX_FREE(array->array);
330         array->array = NULL;
331         array->length = 0;
332 
333 cleanup:
334 
335         PKIX_RETURN(BYTEARRAY);
336 }
337 
338 /*
339  * FUNCTION: pkix_pl_ByteArray_Hashcode
340  * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
341  */
342 static PKIX_Error *
pkix_pl_ByteArray_Hashcode(PKIX_PL_Object * object,PKIX_UInt32 * pHashcode,void * plContext)343 pkix_pl_ByteArray_Hashcode(
344         PKIX_PL_Object *object,
345         PKIX_UInt32 *pHashcode,
346         void *plContext)
347 {
348         PKIX_PL_ByteArray *array = NULL;
349 
350         PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Hashcode");
351         PKIX_NULLCHECK_TWO(object, pHashcode);
352 
353         PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext),
354                     PKIX_OBJECTNOTBYTEARRAY);
355 
356         array = (PKIX_PL_ByteArray*)object;
357 
358         PKIX_CHECK(pkix_hash
359                 ((const unsigned char *)array->array,
360                 array->length,
361                 pHashcode,
362                 plContext),
363                 PKIX_HASHFAILED);
364 
365 cleanup:
366 
367         PKIX_RETURN(BYTEARRAY);
368 }
369 
370 /*
371  * FUNCTION: pkix_pl_ByteArray_RegisterSelf
372  * DESCRIPTION:
373  * Registers PKIX_BYTEARRAY_TYPE and its related functions with systemClasses[]
374  * THREAD SAFETY:
375  *  Not Thread Safe - for performance and complexity reasons
376  *
377  *  Since this function is only called by PKIX_PL_Initialize, which should
378  *  only be called once, it is acceptable that this function is not
379  *  thread-safe.
380  */
381 PKIX_Error *
pkix_pl_ByteArray_RegisterSelf(void * plContext)382 pkix_pl_ByteArray_RegisterSelf(void *plContext)
383 {
384 
385         extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
386         pkix_ClassTable_Entry entry;
387 
388         PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_RegisterSelf");
389 
390         entry.description = "ByteArray";
391         entry.objCounter = 0;
392         entry.typeObjectSize = sizeof(PKIX_PL_ByteArray);
393         entry.destructor = pkix_pl_ByteArray_Destroy;
394         entry.equalsFunction = pkix_pl_ByteArray_Equals;
395         entry.hashcodeFunction = pkix_pl_ByteArray_Hashcode;
396         entry.toStringFunction = pkix_pl_ByteArray_ToString;
397         entry.comparator = NULL;
398         entry.duplicateFunction = pkix_duplicateImmutable;
399 
400         systemClasses[PKIX_BYTEARRAY_TYPE] = entry;
401 
402         PKIX_RETURN(BYTEARRAY);
403 }
404 
405 /* --Public-Functions------------------------------------------------------- */
406 
407 /*
408  * FUNCTION: PKIX_PL_ByteArray_Create (see comments in pkix_pl_system.h)
409  */
410 PKIX_Error *
PKIX_PL_ByteArray_Create(void * array,PKIX_UInt32 length,PKIX_PL_ByteArray ** pByteArray,void * plContext)411 PKIX_PL_ByteArray_Create(
412         void *array,
413         PKIX_UInt32 length,
414         PKIX_PL_ByteArray **pByteArray,
415         void *plContext)
416 {
417         PKIX_PL_ByteArray *byteArray = NULL;
418 
419         PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_Create");
420         PKIX_NULLCHECK_ONE(pByteArray);
421 
422         PKIX_CHECK(PKIX_PL_Object_Alloc
423                 (PKIX_BYTEARRAY_TYPE,
424                 sizeof (PKIX_PL_ByteArray),
425                 (PKIX_PL_Object **)&byteArray,
426                 plContext),
427                 PKIX_COULDNOTCREATEOBJECTSTORAGE);
428 
429         byteArray->length = length;
430         byteArray->array = NULL;
431 
432         if (length != 0){
433                 /* Alloc space for array */
434                 PKIX_NULLCHECK_ONE(array);
435 
436                 PKIX_CHECK(PKIX_PL_Malloc
437                             (length, (void**)&(byteArray->array), plContext),
438                             PKIX_MALLOCFAILED);
439 
440                 PKIX_BYTEARRAY_DEBUG("\tCalling PORT_Memcpy).\n");
441                 (void) PORT_Memcpy(byteArray->array, array, length);
442         }
443 
444         *pByteArray = byteArray;
445 
446 cleanup:
447 
448         if (PKIX_ERROR_RECEIVED){
449                 PKIX_DECREF(byteArray);
450         }
451 
452         PKIX_RETURN(BYTEARRAY);
453 }
454 
455 /*
456  * FUNCTION: PKIX_PL_ByteArray_GetPointer (see comments in pkix_pl_system.h)
457  */
458 PKIX_Error *
PKIX_PL_ByteArray_GetPointer(PKIX_PL_ByteArray * byteArray,void ** pArray,void * plContext)459 PKIX_PL_ByteArray_GetPointer(
460         PKIX_PL_ByteArray *byteArray,
461         void **pArray,
462         void *plContext)
463 {
464         void *bytes = NULL;
465         PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_GetPointer");
466         PKIX_NULLCHECK_TWO(byteArray, pArray);
467 
468         if (byteArray->length != 0){
469                 PKIX_CHECK(PKIX_PL_Malloc
470                             (byteArray->length, &bytes, plContext),
471                             PKIX_MALLOCFAILED);
472 
473                 PKIX_BYTEARRAY_DEBUG("\tCalling PORT_Memcpy).\n");
474                 (void) PORT_Memcpy
475                         (bytes, byteArray->array, byteArray->length);
476         }
477 
478         *pArray = bytes;
479 
480 cleanup:
481 
482         if (PKIX_ERROR_RECEIVED){
483                 PKIX_FREE(bytes);
484         }
485 
486         PKIX_RETURN(BYTEARRAY);
487 }
488 
489 /*
490  * FUNCTION: PKIX_PL_ByteArray_GetLength (see comments in pkix_pl_system.h)
491  */
492 PKIX_Error *
PKIX_PL_ByteArray_GetLength(PKIX_PL_ByteArray * byteArray,PKIX_UInt32 * pLength,void * plContext)493 PKIX_PL_ByteArray_GetLength(
494         PKIX_PL_ByteArray *byteArray,
495         PKIX_UInt32 *pLength,
496         void *plContext)
497 {
498         PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_GetLength");
499         PKIX_NULLCHECK_TWO(byteArray, pLength);
500 
501         *pLength = byteArray->length;
502 
503         PKIX_RETURN(BYTEARRAY);
504 }
505