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_publickey.c
6  *
7  * Certificate Object Functions
8  *
9  */
10 
11 #include "pkix_pl_publickey.h"
12 
13 /* --Private-Cert-Functions------------------------------------- */
14 
15 /*
16  * FUNCTION: pkix_pl_PublicKey_ToString_Helper
17  * DESCRIPTION:
18  *
19  *  Helper function that creates a string representation of the PublicKey
20  *  pointed to by "pkixPubKey" and stores it at "pString".
21  *
22  * PARAMETERS
23  *  "pkixPubKey"
24  *      Address of PublicKey whose string representation is desired.
25  *      Must be non-NULL.
26  *  "pString"
27  *      Address where object pointer will be stored. Must be non-NULL.
28  *  "plContext" - Platform-specific context pointer.
29  * THREAD SAFETY:
30  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
31  * RETURNS:
32  *  Returns NULL if the function succeeds.
33  *  Returns a PublicKey Error if the function fails in a non-fatal way.
34  *  Returns a Fatal Error if the function fails in an unrecoverable way.
35  */
36 static PKIX_Error *
pkix_pl_PublicKey_ToString_Helper(PKIX_PL_PublicKey * pkixPubKey,PKIX_PL_String ** pString,void * plContext)37 pkix_pl_PublicKey_ToString_Helper(
38         PKIX_PL_PublicKey *pkixPubKey,
39         PKIX_PL_String **pString,
40         void *plContext)
41 {
42         SECAlgorithmID algorithm;
43         SECOidTag pubKeyTag;
44         char *asciiOID = NULL;
45         PKIX_Boolean freeAsciiOID = PKIX_FALSE;
46         SECItem oidBytes;
47 
48         PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_ToString_Helper");
49         PKIX_NULLCHECK_THREE(pkixPubKey, pkixPubKey->nssSPKI, pString);
50 
51         /*
52          * XXX for now, we print out public key algorithm's
53          * description - add params and bytes later
54          */
55 
56         /*
57          * If the algorithm OID is known to NSS,
58          * we print out the ASCII description that is
59          * registered with NSS. Otherwise, if unknown,
60          * we print out the OID numbers (eg. "1.2.840.3")
61          */
62 
63         algorithm = pkixPubKey->nssSPKI->algorithm;
64 
65         PKIX_PUBLICKEY_DEBUG("\t\tCalling SECOID_GetAlgorithmTag).\n");
66         pubKeyTag = SECOID_GetAlgorithmTag(&algorithm);
67         if (pubKeyTag != SEC_OID_UNKNOWN){
68                 PKIX_PUBLICKEY_DEBUG
69                         ("\t\tCalling SECOID_FindOIDTagDescription).\n");
70                 asciiOID = (char *)SECOID_FindOIDTagDescription(pubKeyTag);
71                 if (!asciiOID){
72                         PKIX_ERROR(PKIX_SECOIDFINDOIDTAGDESCRIPTIONFAILED);
73                 }
74         } else { /* pubKeyTag == SEC_OID_UNKNOWN */
75                 oidBytes = algorithm.algorithm;
76                 PKIX_CHECK(pkix_pl_oidBytes2Ascii
77                             (&oidBytes, &asciiOID, plContext),
78                             PKIX_OIDBYTES2ASCIIFAILED);
79                 freeAsciiOID = PKIX_TRUE;
80         }
81 
82         PKIX_CHECK(PKIX_PL_String_Create
83                 (PKIX_ESCASCII, (void *)asciiOID, 0, pString, plContext),
84                 PKIX_UNABLETOCREATEPSTRING);
85 
86 cleanup:
87 
88         /*
89          * we only free asciiOID if it was malloc'ed by pkix_pl_oidBytes2Ascii
90          */
91         if (freeAsciiOID){
92                 PKIX_FREE(asciiOID);
93         }
94 
95         PKIX_RETURN(PUBLICKEY);
96 }
97 
98 /*
99  * FUNCTION: pkix_pl_DestroySPKI
100  * DESCRIPTION:
101  *  Frees all memory associated with the CERTSubjectPublicKeyInfo pointed to
102  *  by "nssSPKI".
103  * PARAMETERS
104  *  "nssSPKI"
105  *      Address of CERTSubjectPublicKeyInfo. Must be non-NULL.
106  *  "plContext" - Platform-specific context pointer.
107  * THREAD SAFETY:
108  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
109  * RETURNS:
110  *  Returns NULL if the function succeeds.
111  *  Returns an Object Error if the function fails in a non-fatal way.
112  *  Returns a Fatal Error if the function fails in an unrecoverable way.
113  */
114 static PKIX_Error *
pkix_pl_DestroySPKI(CERTSubjectPublicKeyInfo * nssSPKI,void * plContext)115 pkix_pl_DestroySPKI(
116         CERTSubjectPublicKeyInfo *nssSPKI,
117         void *plContext)
118 {
119         PKIX_ENTER(PUBLICKEY, "pkix_pl_DestroySPKI");
120 
121         PKIX_NULLCHECK_ONE(nssSPKI);
122 
123         PKIX_PUBLICKEY_DEBUG("\t\tCalling SECOID_DestroyAlgorithmID).\n");
124         SECOID_DestroyAlgorithmID(&nssSPKI->algorithm, PKIX_FALSE);
125 
126         PKIX_PUBLICKEY_DEBUG("\t\tCalling SECITEM_FreeItem).\n");
127         SECITEM_FreeItem(&nssSPKI->subjectPublicKey, PKIX_FALSE);
128 
129         PKIX_RETURN(PUBLICKEY);
130 }
131 
132 /*
133  * FUNCTION: pkix_pl_PublicKey_Destroy
134  * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
135  */
136 static PKIX_Error *
pkix_pl_PublicKey_Destroy(PKIX_PL_Object * object,void * plContext)137 pkix_pl_PublicKey_Destroy(
138         PKIX_PL_Object *object,
139         void *plContext)
140 {
141         PKIX_PL_PublicKey *pubKey = NULL;
142 
143         PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Destroy");
144 
145         PKIX_NULLCHECK_ONE(object);
146 
147         PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext),
148                     PKIX_OBJECTNOTPUBLICKEY);
149 
150         pubKey = (PKIX_PL_PublicKey *)object;
151 
152         if (pubKey->nssSPKI) {
153 
154             PKIX_CHECK(pkix_pl_DestroySPKI(pubKey->nssSPKI, plContext),
155                        PKIX_DESTROYSPKIFAILED);
156 
157             PKIX_FREE(pubKey->nssSPKI);
158         }
159 
160 cleanup:
161 
162         PKIX_RETURN(PUBLICKEY);
163 }
164 
165 /*
166  * FUNCTION: pkix_pl_PublicKey_ToString
167  * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
168  */
169 static PKIX_Error *
pkix_pl_PublicKey_ToString(PKIX_PL_Object * object,PKIX_PL_String ** pString,void * plContext)170 pkix_pl_PublicKey_ToString(
171         PKIX_PL_Object *object,
172         PKIX_PL_String **pString,
173         void *plContext)
174 {
175         PKIX_PL_PublicKey *pkixPubKey = NULL;
176         PKIX_PL_String *pubKeyString = NULL;
177 
178         PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_toString");
179         PKIX_NULLCHECK_TWO(object, pString);
180 
181         PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext),
182                     PKIX_OBJECTNOTPUBLICKEY);
183 
184         pkixPubKey = (PKIX_PL_PublicKey *)object;
185 
186         PKIX_CHECK(pkix_pl_PublicKey_ToString_Helper
187                     (pkixPubKey, &pubKeyString, plContext),
188                     PKIX_PUBLICKEYTOSTRINGHELPERFAILED);
189 
190         *pString = pubKeyString;
191 
192 cleanup:
193 
194         PKIX_RETURN(PUBLICKEY);
195 }
196 
197 /*
198  * FUNCTION: pkix_pl_PublicKey_Hashcode
199  * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
200  */
201 static PKIX_Error *
pkix_pl_PublicKey_Hashcode(PKIX_PL_Object * object,PKIX_UInt32 * pHashcode,void * plContext)202 pkix_pl_PublicKey_Hashcode(
203         PKIX_PL_Object *object,
204         PKIX_UInt32 *pHashcode,
205         void *plContext)
206 {
207         PKIX_PL_PublicKey *pkixPubKey = NULL;
208         SECItem algOID;
209         SECItem algParams;
210         SECItem nssPubKey;
211         PKIX_UInt32 algOIDHash;
212         PKIX_UInt32 algParamsHash;
213         PKIX_UInt32 pubKeyHash;
214 
215         PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Hashcode");
216         PKIX_NULLCHECK_TWO(object, pHashcode);
217 
218         PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext),
219                     PKIX_OBJECTNOTPUBLICKEY);
220 
221         pkixPubKey = (PKIX_PL_PublicKey *)object;
222 
223         PKIX_NULLCHECK_ONE(pkixPubKey->nssSPKI);
224 
225         algOID = pkixPubKey->nssSPKI->algorithm.algorithm;
226         algParams = pkixPubKey->nssSPKI->algorithm.parameters;
227         nssPubKey = pkixPubKey->nssSPKI->subjectPublicKey;
228 
229         PKIX_CHECK(pkix_hash
230                     (algOID.data, algOID.len, &algOIDHash, plContext),
231                     PKIX_HASHFAILED);
232 
233         PKIX_CHECK(pkix_hash
234                     (algParams.data, algParams.len, &algParamsHash, plContext),
235                     PKIX_HASHFAILED);
236 
237         PKIX_CHECK(pkix_hash
238                     (nssPubKey.data, nssPubKey.len, &pubKeyHash, plContext),
239                     PKIX_HASHFAILED);
240 
241         *pHashcode = pubKeyHash;
242 
243 cleanup:
244 
245         PKIX_RETURN(PUBLICKEY);
246 }
247 
248 
249 /*
250  * FUNCTION: pkix_pl_PublicKey_Equals
251  * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
252  */
253 static PKIX_Error *
pkix_pl_PublicKey_Equals(PKIX_PL_Object * firstObject,PKIX_PL_Object * secondObject,PKIX_Boolean * pResult,void * plContext)254 pkix_pl_PublicKey_Equals(
255         PKIX_PL_Object *firstObject,
256         PKIX_PL_Object *secondObject,
257         PKIX_Boolean *pResult,
258         void *plContext)
259 {
260         PKIX_PL_PublicKey *firstPKIXPubKey = NULL;
261         PKIX_PL_PublicKey *secondPKIXPubKey = NULL;
262         CERTSubjectPublicKeyInfo *firstSPKI = NULL;
263         CERTSubjectPublicKeyInfo *secondSPKI = NULL;
264         SECComparison cmpResult;
265         PKIX_UInt32 secondType;
266 
267         PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Equals");
268         PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
269 
270         /* test that firstObject is a PublicKey */
271         PKIX_CHECK(pkix_CheckType(firstObject, PKIX_PUBLICKEY_TYPE, plContext),
272                 PKIX_FIRSTOBJECTNOTPUBLICKEY);
273 
274         /*
275          * Since we know firstObject is a PublicKey, if both references are
276          * identical, they must be equal
277          */
278         if (firstObject == secondObject){
279                 *pResult = PKIX_TRUE;
280                 goto cleanup;
281         }
282 
283         /*
284          * If secondObject isn't a PublicKey, we don't throw an error.
285          * We simply return a Boolean result of FALSE
286          */
287         *pResult = PKIX_FALSE;
288         PKIX_CHECK(PKIX_PL_Object_GetType
289                     (secondObject, &secondType, plContext),
290                     PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
291         if (secondType != PKIX_PUBLICKEY_TYPE) goto cleanup;
292 
293         firstPKIXPubKey = ((PKIX_PL_PublicKey *)firstObject);
294         secondPKIXPubKey = (PKIX_PL_PublicKey *)secondObject;
295 
296         firstSPKI = firstPKIXPubKey->nssSPKI;
297         secondSPKI = secondPKIXPubKey->nssSPKI;
298 
299         PKIX_NULLCHECK_TWO(firstSPKI, secondSPKI);
300 
301         PKIX_PL_NSSCALLRV(PUBLICKEY, cmpResult, SECOID_CompareAlgorithmID,
302                         (&firstSPKI->algorithm, &secondSPKI->algorithm));
303 
304         if (cmpResult == SECEqual){
305                 PKIX_PUBLICKEY_DEBUG("\t\tCalling SECITEM_CompareItem).\n");
306                 cmpResult = SECITEM_CompareItem
307                                 (&firstSPKI->subjectPublicKey,
308                                 &secondSPKI->subjectPublicKey);
309         }
310 
311         *pResult = (cmpResult == SECEqual)?PKIX_TRUE:PKIX_FALSE;
312 
313 cleanup:
314 
315         PKIX_RETURN(PUBLICKEY);
316 }
317 
318 /*
319  * FUNCTION: pkix_pl_PublicKey_RegisterSelf
320  * DESCRIPTION:
321  *  Registers PKIX_PUBLICKEY_TYPE and its related functions with systemClasses[]
322  * THREAD SAFETY:
323  *  Not Thread Safe - for performance and complexity reasons
324  *
325  *  Since this function is only called by PKIX_PL_Initialize, which should
326  *  only be called once, it is acceptable that this function is not
327  *  thread-safe.
328  */
329 PKIX_Error *
pkix_pl_PublicKey_RegisterSelf(void * plContext)330 pkix_pl_PublicKey_RegisterSelf(void *plContext)
331 {
332 
333         extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
334         pkix_ClassTable_Entry entry;
335 
336         PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_RegisterSelf");
337 
338         entry.description = "PublicKey";
339         entry.objCounter = 0;
340         entry.typeObjectSize = sizeof(PKIX_PL_PublicKey);
341         entry.destructor = pkix_pl_PublicKey_Destroy;
342         entry.equalsFunction = pkix_pl_PublicKey_Equals;
343         entry.hashcodeFunction = pkix_pl_PublicKey_Hashcode;
344         entry.toStringFunction = pkix_pl_PublicKey_ToString;
345         entry.comparator = NULL;
346         entry.duplicateFunction = pkix_duplicateImmutable;
347         systemClasses[PKIX_PUBLICKEY_TYPE] = entry;
348 
349         PKIX_RETURN(PUBLICKEY);
350 }
351 
352 /* --Public-Functions------------------------------------------------------- */
353 
354 /*
355  * FUNCTION: PKIX_PL_PublicKey_NeedsDSAParameters
356  *              (see comments in pkix_pl_pki.h)
357  */
358 PKIX_Error *
PKIX_PL_PublicKey_NeedsDSAParameters(PKIX_PL_PublicKey * pubKey,PKIX_Boolean * pNeedsParams,void * plContext)359 PKIX_PL_PublicKey_NeedsDSAParameters(
360         PKIX_PL_PublicKey *pubKey,
361         PKIX_Boolean *pNeedsParams,
362         void *plContext)
363 {
364         CERTSubjectPublicKeyInfo *nssSPKI = NULL;
365         KeyType pubKeyType;
366         PKIX_Boolean needsParams = PKIX_FALSE;
367 
368         PKIX_ENTER(PUBLICKEY, "PKIX_PL_PublicKey_NeedsDSAParameters");
369         PKIX_NULLCHECK_TWO(pubKey, pNeedsParams);
370 
371         nssSPKI = pubKey->nssSPKI;
372 
373         PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n");
374         pubKeyType = CERT_GetCertKeyType(nssSPKI);
375         if (!pubKeyType){
376                 PKIX_ERROR(PKIX_PUBKEYTYPENULLKEY);
377         }
378 
379         if ((pubKeyType == dsaKey) &&
380             (nssSPKI->algorithm.parameters.len == 0)){
381                 needsParams = PKIX_TRUE;
382         }
383 
384         *pNeedsParams = needsParams;
385 
386 cleanup:
387 
388         PKIX_RETURN(PUBLICKEY);
389 }
390 
391 /*
392  * FUNCTION: PKIX_PL_PublicKey_MakeInheritedDSAPublicKey
393  *              (see comments in pkix_pl_pki.h)
394  */
395 PKIX_Error *
PKIX_PL_PublicKey_MakeInheritedDSAPublicKey(PKIX_PL_PublicKey * firstKey,PKIX_PL_PublicKey * secondKey,PKIX_PL_PublicKey ** pResultKey,void * plContext)396 PKIX_PL_PublicKey_MakeInheritedDSAPublicKey(
397         PKIX_PL_PublicKey *firstKey,
398         PKIX_PL_PublicKey *secondKey,
399         PKIX_PL_PublicKey **pResultKey,
400         void *plContext)
401 {
402         CERTSubjectPublicKeyInfo *firstSPKI = NULL;
403         CERTSubjectPublicKeyInfo *secondSPKI = NULL;
404         CERTSubjectPublicKeyInfo *thirdSPKI = NULL;
405         PKIX_PL_PublicKey *resultKey = NULL;
406         KeyType firstPubKeyType;
407         KeyType secondPubKeyType;
408         SECStatus rv;
409 
410         PKIX_ENTER(PUBLICKEY, "PKIX_PL_PublicKey_MakeInheritedDSAPublicKey");
411         PKIX_NULLCHECK_THREE(firstKey, secondKey, pResultKey);
412         PKIX_NULLCHECK_TWO(firstKey->nssSPKI, secondKey->nssSPKI);
413 
414         firstSPKI = firstKey->nssSPKI;
415         secondSPKI = secondKey->nssSPKI;
416 
417         PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n");
418         firstPubKeyType = CERT_GetCertKeyType(firstSPKI);
419         if (!firstPubKeyType){
420                 PKIX_ERROR(PKIX_FIRSTPUBKEYTYPENULLKEY);
421         }
422 
423         PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n");
424         secondPubKeyType = CERT_GetCertKeyType(secondSPKI);
425         if (!secondPubKeyType){
426                 PKIX_ERROR(PKIX_SECONDPUBKEYTYPENULLKEY);
427         }
428 
429         if ((firstPubKeyType == dsaKey) &&
430             (firstSPKI->algorithm.parameters.len == 0)){
431                 if (secondPubKeyType != dsaKey) {
432                         PKIX_ERROR(PKIX_SECONDKEYNOTDSAPUBLICKEY);
433                 } else if (secondSPKI->algorithm.parameters.len == 0) {
434                         PKIX_ERROR
435                                 (PKIX_SECONDKEYDSAPUBLICKEY);
436                 } else {
437                         PKIX_CHECK(PKIX_PL_Calloc
438                                     (1,
439                                     sizeof (CERTSubjectPublicKeyInfo),
440                                     (void **)&thirdSPKI,
441                                     plContext),
442                                     PKIX_CALLOCFAILED);
443 
444                         PKIX_PUBLICKEY_DEBUG
445                                 ("\t\tCalling"
446                                 "SECKEY_CopySubjectPublicKeyInfo).\n");
447                         rv = SECKEY_CopySubjectPublicKeyInfo
448                                 (NULL, thirdSPKI, firstSPKI);
449                         if (rv != SECSuccess) {
450                             PKIX_ERROR
451                                     (PKIX_SECKEYCOPYSUBJECTPUBLICKEYINFOFAILED);
452                         }
453 
454                         PKIX_PUBLICKEY_DEBUG
455                                 ("\t\tCalling SECITEM_CopyItem).\n");
456                         rv = SECITEM_CopyItem(NULL,
457                                             &thirdSPKI->algorithm.parameters,
458                                             &secondSPKI->algorithm.parameters);
459 
460                         if (rv != SECSuccess) {
461                                 PKIX_ERROR(PKIX_OUTOFMEMORY);
462                         }
463 
464                         /* create a PKIX_PL_PublicKey object */
465                         PKIX_CHECK(PKIX_PL_Object_Alloc
466                                     (PKIX_PUBLICKEY_TYPE,
467                                     sizeof (PKIX_PL_PublicKey),
468                                     (PKIX_PL_Object **)&resultKey,
469                                     plContext),
470                                     PKIX_COULDNOTCREATEOBJECT);
471 
472                         /* populate the SPKI field */
473                         resultKey->nssSPKI = thirdSPKI;
474                         *pResultKey = resultKey;
475                 }
476         } else {
477                 *pResultKey = NULL;
478         }
479 
480 cleanup:
481 
482         if (thirdSPKI && PKIX_ERROR_RECEIVED){
483                 PKIX_CHECK(pkix_pl_DestroySPKI(thirdSPKI, plContext),
484                             PKIX_DESTROYSPKIFAILED);
485                 PKIX_FREE(thirdSPKI);
486         }
487 
488         PKIX_RETURN(PUBLICKEY);
489 }
490