tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }