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_bigint.c
6  *
7  * BigInt Object Functions
8  *
9  */
10 
11 #include "pkix_pl_bigint.h"
12 
13 /* --Private-Big-Int-Functions------------------------------------ */
14 
15 /*
16  * FUNCTION: pkix_pl_BigInt_Comparator
17  * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h)
18  */
19 static PKIX_Error *
pkix_pl_BigInt_Comparator(PKIX_PL_Object * firstObject,PKIX_PL_Object * secondObject,PKIX_Int32 * pResult,void * plContext)20 pkix_pl_BigInt_Comparator(
21         PKIX_PL_Object *firstObject,
22         PKIX_PL_Object *secondObject,
23         PKIX_Int32 *pResult,
24         void *plContext)
25 {
26         PKIX_PL_BigInt *firstBigInt = NULL;
27         PKIX_PL_BigInt *secondBigInt = NULL;
28         char *firstPtr = NULL;
29         char *secondPtr = NULL;
30         PKIX_UInt32 firstLen, secondLen;
31 
32         PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Comparator");
33         PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
34 
35         PKIX_CHECK(pkix_CheckTypes
36                     (firstObject, secondObject, PKIX_BIGINT_TYPE, plContext),
37                     PKIX_ARGUMENTSNOTBIGINTS);
38 
39         /* It's safe to cast */
40         firstBigInt = (PKIX_PL_BigInt*)firstObject;
41         secondBigInt = (PKIX_PL_BigInt*)secondObject;
42 
43         *pResult = 0;
44         firstPtr = firstBigInt->dataRep;
45         secondPtr = secondBigInt->dataRep;
46         firstLen = firstBigInt->length;
47         secondLen = secondBigInt->length;
48 
49         if (firstLen < secondLen) {
50                 *pResult = -1;
51         } else if (firstLen > secondLen) {
52                 *pResult = 1;
53         } else if (firstLen == secondLen) {
54                 PKIX_BIGINT_DEBUG("\t\tCalling PORT_Memcmp).\n");
55                 *pResult = PORT_Memcmp(firstPtr, secondPtr, firstLen);
56         }
57 
58 cleanup:
59 
60         PKIX_RETURN(BIGINT);
61 }
62 
63 /*
64  * FUNCTION: pkix_pl_BigInt_Destroy
65  * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
66  */
67 static PKIX_Error *
pkix_pl_BigInt_Destroy(PKIX_PL_Object * object,void * plContext)68 pkix_pl_BigInt_Destroy(
69         PKIX_PL_Object *object,
70         void *plContext)
71 {
72         PKIX_PL_BigInt *bigInt = NULL;
73 
74         PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Destroy");
75         PKIX_NULLCHECK_ONE(object);
76 
77         PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext),
78                     PKIX_OBJECTNOTBIGINT);
79 
80         bigInt = (PKIX_PL_BigInt*)object;
81 
82         PKIX_FREE(bigInt->dataRep);
83         bigInt->dataRep = NULL;
84         bigInt->length = 0;
85 
86 cleanup:
87 
88         PKIX_RETURN(BIGINT);
89 }
90 
91 
92 /*
93  * FUNCTION: pkix_pl_BigInt_ToString
94  * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
95  */
96 static PKIX_Error *
pkix_pl_BigInt_ToString(PKIX_PL_Object * object,PKIX_PL_String ** pString,void * plContext)97 pkix_pl_BigInt_ToString(
98         PKIX_PL_Object *object,
99         PKIX_PL_String **pString,
100         void *plContext)
101 {
102         PKIX_PL_BigInt *bigInt = NULL;
103         char *outputText = NULL;
104         PKIX_UInt32 i, j, lengthChars;
105 
106         PKIX_ENTER(BIGINT, "pkix_pl_BigInt_ToString");
107         PKIX_NULLCHECK_TWO(object, pString);
108 
109         PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext),
110                     PKIX_OBJECTNOTBIGINT);
111 
112         bigInt = (PKIX_PL_BigInt*)object;
113 
114         /* number of chars = 2 * (number of bytes) + null terminator */
115         lengthChars = (bigInt->length * 2) + 1;
116 
117         PKIX_CHECK(PKIX_PL_Malloc
118                     (lengthChars, (void **)&outputText, plContext),
119                     PKIX_MALLOCFAILED);
120 
121         for (i = 0, j = 0; i < bigInt->length; i += 1, j += 2){
122                 outputText[j] = pkix_i2hex
123                         ((char) ((*(bigInt->dataRep+i) & 0xf0) >> 4));
124                 outputText[j+1] = pkix_i2hex
125                         ((char) (*(bigInt->dataRep+i) & 0x0f));
126         }
127 
128         outputText[lengthChars-1] = '\0';
129 
130         PKIX_CHECK(PKIX_PL_String_Create
131                     (PKIX_ESCASCII,
132                     outputText,
133                     0,
134                     pString,
135                     plContext),
136                     PKIX_STRINGCREATEFAILED);
137 
138 cleanup:
139 
140         PKIX_FREE(outputText);
141 
142         PKIX_RETURN(BIGINT);
143 }
144 
145 
146 /*
147  * FUNCTION: pkix_pl_BigInt_Hashcode
148  * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
149  */
150 static PKIX_Error *
pkix_pl_BigInt_Hashcode(PKIX_PL_Object * object,PKIX_UInt32 * pHashcode,void * plContext)151 pkix_pl_BigInt_Hashcode(
152         PKIX_PL_Object *object,
153         PKIX_UInt32 *pHashcode,
154         void *plContext)
155 {
156         PKIX_PL_BigInt *bigInt = NULL;
157 
158         PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Hashcode");
159         PKIX_NULLCHECK_TWO(object, pHashcode);
160 
161         PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext),
162                     PKIX_OBJECTNOTBIGINT);
163 
164         bigInt = (PKIX_PL_BigInt*)object;
165 
166         PKIX_CHECK(pkix_hash
167                     ((void *)bigInt->dataRep,
168                     bigInt->length,
169                     pHashcode,
170                     plContext),
171                     PKIX_HASHFAILED);
172 
173 cleanup:
174 
175         PKIX_RETURN(BIGINT);
176 }
177 
178 /*
179  * FUNCTION: pkix_pl_BigInt_Equals
180  * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
181  */
182 static PKIX_Error *
pkix_pl_BigInt_Equals(PKIX_PL_Object * first,PKIX_PL_Object * second,PKIX_Boolean * pResult,void * plContext)183 pkix_pl_BigInt_Equals(
184         PKIX_PL_Object *first,
185         PKIX_PL_Object *second,
186         PKIX_Boolean *pResult,
187         void *plContext)
188 {
189         PKIX_UInt32 secondType;
190         PKIX_Int32 cmpResult = 0;
191 
192         PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Equals");
193         PKIX_NULLCHECK_THREE(first, second, pResult);
194 
195         PKIX_CHECK(pkix_CheckType(first, PKIX_BIGINT_TYPE, plContext),
196                 PKIX_FIRSTOBJECTNOTBIGINT);
197 
198         PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext),
199                 PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
200 
201         *pResult = PKIX_FALSE;
202 
203         if (secondType != PKIX_BIGINT_TYPE) goto cleanup;
204 
205         PKIX_CHECK(pkix_pl_BigInt_Comparator
206                 (first, second, &cmpResult, plContext),
207                 PKIX_BIGINTCOMPARATORFAILED);
208 
209         *pResult = (cmpResult == 0);
210 
211 cleanup:
212 
213         PKIX_RETURN(BIGINT);
214 }
215 
216 /*
217  * FUNCTION: pkix_pl_BigInt_RegisterSelf
218  * DESCRIPTION:
219  *  Registers PKIX_BIGINT_TYPE and its related functions with systemClasses[]
220  * THREAD SAFETY:
221  *  Not Thread Safe - for performance and complexity reasons
222  *
223  *  Since this function is only called by PKIX_PL_Initialize, which should
224  *  only be called once, it is acceptable that this function is not
225  *  thread-safe.
226  */
227 PKIX_Error *
pkix_pl_BigInt_RegisterSelf(void * plContext)228 pkix_pl_BigInt_RegisterSelf(void *plContext)
229 {
230 
231         extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
232         pkix_ClassTable_Entry entry;
233 
234         PKIX_ENTER(BIGINT, "pkix_pl_BigInt_RegisterSelf");
235 
236         entry.description = "BigInt";
237         entry.objCounter = 0;
238         entry.typeObjectSize = sizeof(PKIX_PL_BigInt);
239         entry.destructor = pkix_pl_BigInt_Destroy;
240         entry.equalsFunction = pkix_pl_BigInt_Equals;
241         entry.hashcodeFunction = pkix_pl_BigInt_Hashcode;
242         entry.toStringFunction = pkix_pl_BigInt_ToString;
243         entry.comparator = pkix_pl_BigInt_Comparator;
244         entry.duplicateFunction = pkix_duplicateImmutable;
245 
246         systemClasses[PKIX_BIGINT_TYPE] = entry;
247 
248         PKIX_RETURN(BIGINT);
249 }
250 
251 /*
252  * FUNCTION: pkix_pl_BigInt_CreateWithBytes
253  * DESCRIPTION:
254  *
255  *  Creates a new BigInt of size "length" representing the array of bytes
256  *  pointed to by "bytes" and stores it at "pBigInt". The caller should make
257  *  sure that the first byte is not 0x00 (unless it is the the only byte).
258  *  This function does not do that checking.
259  *
260  *  Once created, a PKIX_PL_BigInt object is immutable.
261  *
262  * PARAMETERS:
263  *  "bytes"
264  *      Address of array of bytes. Must be non-NULL.
265  *  "length"
266  *      Length of the array. Must be non-zero.
267  *  "pBigInt"
268  *      Address where object pointer will be stored. Must be non-NULL.
269  *  "plContext" - Platform-specific context pointer.
270  * THREAD SAFETY:
271  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
272  * RETURNS:
273  *  Returns NULL if the function succeeds.
274  *  Returns a Fatal Error if the function fails in an unrecoverable way.
275  */
276 PKIX_Error *
pkix_pl_BigInt_CreateWithBytes(char * bytes,PKIX_UInt32 length,PKIX_PL_BigInt ** pBigInt,void * plContext)277 pkix_pl_BigInt_CreateWithBytes(
278         char *bytes,
279         PKIX_UInt32 length,
280         PKIX_PL_BigInt **pBigInt,
281         void *plContext)
282 {
283         PKIX_PL_BigInt *bigInt = NULL;
284 
285         PKIX_ENTER(BIGINT, "pkix_pl_BigInt_CreateWithBytes");
286         PKIX_NULLCHECK_TWO(pBigInt, bytes);
287 
288         if (length == 0) {
289                 PKIX_ERROR(PKIX_BIGINTLENGTH0INVALID)
290         }
291 
292         PKIX_CHECK(PKIX_PL_Object_Alloc
293                 (PKIX_BIGINT_TYPE,
294                 sizeof (PKIX_PL_BigInt),
295                 (PKIX_PL_Object **)&bigInt,
296                 plContext),
297                 PKIX_COULDNOTCREATEOBJECT);
298 
299         PKIX_CHECK(PKIX_PL_Malloc
300                     (length, (void **)&(bigInt->dataRep), plContext),
301                     PKIX_MALLOCFAILED);
302 
303         PKIX_BIGINT_DEBUG("\t\tCalling PORT_Memcpy).\n");
304         (void) PORT_Memcpy(bigInt->dataRep, bytes, length);
305 
306         bigInt->length = length;
307 
308         *pBigInt = bigInt;
309 
310 cleanup:
311 
312         if (PKIX_ERROR_RECEIVED){
313                 PKIX_DECREF(bigInt);
314         }
315 
316         PKIX_RETURN(BIGINT);
317 }
318 
319 /* --Public-Functions------------------------------------------------------- */
320 
321 /*
322  * FUNCTION: PKIX_PL_BigInt_Create (see comments in pkix_pl_system.h)
323  */
324 PKIX_Error *
PKIX_PL_BigInt_Create(PKIX_PL_String * stringRep,PKIX_PL_BigInt ** pBigInt,void * plContext)325 PKIX_PL_BigInt_Create(
326         PKIX_PL_String *stringRep,
327         PKIX_PL_BigInt **pBigInt,
328         void *plContext)
329 {
330         PKIX_PL_BigInt *bigInt = NULL;
331         char *asciiString = NULL;
332         PKIX_UInt32 lengthBytes;
333         PKIX_UInt32 lengthString;
334         PKIX_UInt32 i;
335         char currChar;
336 
337         PKIX_ENTER(BIGINT, "PKIX_PL_BigInt_Create");
338         PKIX_NULLCHECK_TWO(pBigInt, stringRep);
339 
340         PKIX_CHECK(PKIX_PL_String_GetEncoded
341                 (stringRep,
342                 PKIX_ESCASCII,
343                 (void **)&asciiString,
344                 &lengthString,
345                 plContext),
346                 PKIX_STRINGGETENCODEDFAILED);
347 
348         if ((lengthString == 0) || ((lengthString % 2) != 0)){
349                 PKIX_ERROR(PKIX_SOURCESTRINGHASINVALIDLENGTH);
350         }
351 
352         if (lengthString != 2){
353                 if ((asciiString[0] == '0') && (asciiString[1] == '0')){
354                         PKIX_ERROR(PKIX_FIRSTDOUBLEHEXMUSTNOTBE00);
355                 }
356         }
357 
358         for (i = 0; i < lengthString; i++) {
359                 currChar = asciiString[i];
360                 if (!PKIX_ISXDIGIT(currChar)){
361                         PKIX_ERROR(PKIX_INVALIDCHARACTERINBIGINT);
362                 }
363         }
364 
365         PKIX_CHECK(PKIX_PL_Object_Alloc
366                 (PKIX_BIGINT_TYPE,
367                 sizeof (PKIX_PL_BigInt),
368                 (PKIX_PL_Object **)&bigInt,
369                 plContext),
370                 PKIX_COULDNOTCREATEOBJECT);
371 
372         /* number of bytes = 0.5 * (number of chars) */
373         lengthBytes = lengthString/2;
374 
375         PKIX_CHECK(PKIX_PL_Malloc
376                     (lengthBytes, (void **)&(bigInt->dataRep), plContext),
377                     PKIX_MALLOCFAILED);
378 
379         for (i = 0; i < lengthString; i += 2){
380                 (bigInt->dataRep)[i/2] =
381                         (pkix_hex2i(asciiString[i])<<4) |
382                         pkix_hex2i(asciiString[i+1]);
383         }
384 
385         bigInt->length = lengthBytes;
386 
387         *pBigInt = bigInt;
388 
389 cleanup:
390 
391         PKIX_FREE(asciiString);
392 
393         if (PKIX_ERROR_RECEIVED){
394                 PKIX_DECREF(bigInt);
395         }
396 
397         PKIX_RETURN(BIGINT);
398 }
399