pkix_pl_publickey.c (16030B)
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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 }