tor-browser

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

pkix_targetcertchecker.c (18702B)


      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_targetcertchecker.c
      6 *
      7 * Functions for target cert validation
      8 *
      9 */
     10 
     11 
     12 #include "pkix_targetcertchecker.h"
     13 
     14 /* --Private-TargetCertCheckerState-Functions------------------------------- */
     15 
     16 /*
     17 * FUNCTION: pkix_TargetCertCheckerState_Destroy
     18 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
     19 */
     20 static PKIX_Error *
     21 pkix_TargetCertCheckerState_Destroy(
     22        PKIX_PL_Object *object,
     23        void *plContext)
     24 {
     25        pkix_TargetCertCheckerState *state = NULL;
     26 
     27        PKIX_ENTER(TARGETCERTCHECKERSTATE,
     28                    "pkix_TargetCertCheckerState_Destroy");
     29        PKIX_NULLCHECK_ONE(object);
     30 
     31        /* Check that this object is a target cert checker state */
     32        PKIX_CHECK(pkix_CheckType
     33                    (object, PKIX_TARGETCERTCHECKERSTATE_TYPE, plContext),
     34                    PKIX_OBJECTNOTTARGETCERTCHECKERSTATE);
     35 
     36        state = (pkix_TargetCertCheckerState *)object;
     37 
     38        PKIX_DECREF(state->certSelector);
     39        PKIX_DECREF(state->extKeyUsageOID);
     40        PKIX_DECREF(state->subjAltNameOID);
     41        PKIX_DECREF(state->pathToNameList);
     42        PKIX_DECREF(state->extKeyUsageList);
     43        PKIX_DECREF(state->subjAltNameList);
     44 
     45 cleanup:
     46 
     47        PKIX_RETURN(TARGETCERTCHECKERSTATE);
     48 }
     49 
     50 /*
     51 * FUNCTION: pkix_TargetCertCheckerState_RegisterSelf
     52 * DESCRIPTION:
     53 *  Registers PKIX_TARGETCERTCHECKERSTATE_TYPE and its related functions with
     54 *  systemClasses[]
     55 * THREAD SAFETY:
     56 *  Not Thread Safe - for performance and complexity reasons
     57 *
     58 *  Since this function is only called by PKIX_PL_Initialize, which should
     59 *  only be called once, it is acceptable that this function is not
     60 *  thread-safe.
     61 */
     62 PKIX_Error *
     63 pkix_TargetCertCheckerState_RegisterSelf(void *plContext)
     64 {
     65        extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
     66        pkix_ClassTable_Entry entry;
     67 
     68        PKIX_ENTER(TARGETCERTCHECKERSTATE,
     69                    "pkix_TargetCertCheckerState_RegisterSelf");
     70 
     71        entry.description = "TargetCertCheckerState";
     72        entry.objCounter = 0;
     73        entry.typeObjectSize = sizeof(pkix_TargetCertCheckerState);
     74        entry.destructor = pkix_TargetCertCheckerState_Destroy;
     75        entry.equalsFunction = NULL;
     76        entry.hashcodeFunction = NULL;
     77        entry.toStringFunction = NULL;
     78        entry.comparator = NULL;
     79        entry.duplicateFunction = NULL;
     80 
     81        systemClasses[PKIX_TARGETCERTCHECKERSTATE_TYPE] = entry;
     82 
     83        PKIX_RETURN(TARGETCERTCHECKERSTATE);
     84 }
     85 
     86 /*
     87 * FUNCTION: pkix_TargetCertCheckerState_Create
     88 * DESCRIPTION:
     89 *
     90 *  Creates a new TargetCertCheckerState using the CertSelector pointed to
     91 *  by "certSelector" and the number of certs represented by "certsRemaining"
     92 *  and stores it at "pState".
     93 *
     94 * PARAMETERS:
     95 *  "certSelector"
     96 *      Address of CertSelector representing the criteria against which the
     97 *      final certificate in a chain is to be matched. Must be non-NULL.
     98 *  "certsRemaining"
     99 *      Number of certificates remaining in the chain.
    100 *  "pState"
    101 *      Address where object pointer will be stored. Must be non-NULL.
    102 *  "plContext"
    103 *      Platform-specific context pointer.
    104 * THREAD SAFETY:
    105 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    106 * RETURNS:
    107 *  Returns NULL if the function succeeds.
    108 *  Returns a TargetCertCheckerState Error if the function fails in a
    109 *      non-fatal way.
    110 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    111 */
    112 PKIX_Error *
    113 pkix_TargetCertCheckerState_Create(
    114    PKIX_CertSelector *certSelector,
    115    PKIX_UInt32 certsRemaining,
    116    pkix_TargetCertCheckerState **pState,
    117    void *plContext)
    118 {
    119        pkix_TargetCertCheckerState *state = NULL;
    120        PKIX_ComCertSelParams *certSelectorParams = NULL;
    121        PKIX_List *pathToNameList = NULL;
    122        PKIX_List *extKeyUsageList = NULL;
    123        PKIX_List *subjAltNameList = NULL;
    124        PKIX_PL_OID *extKeyUsageOID = NULL;
    125        PKIX_PL_OID *subjAltNameOID = NULL;
    126        PKIX_Boolean subjAltNameMatchAll = PKIX_TRUE;
    127 
    128        PKIX_ENTER(TARGETCERTCHECKERSTATE,
    129                    "pkix_TargetCertCheckerState_Create");
    130        PKIX_NULLCHECK_ONE(pState);
    131 
    132        PKIX_CHECK(PKIX_PL_OID_Create
    133                    (PKIX_EXTENDEDKEYUSAGE_OID,
    134                    &extKeyUsageOID,
    135                    plContext),
    136                    PKIX_OIDCREATEFAILED);
    137 
    138        PKIX_CHECK(PKIX_PL_OID_Create
    139                    (PKIX_CERTSUBJALTNAME_OID,
    140                    &subjAltNameOID,
    141                    plContext),
    142                    PKIX_OIDCREATEFAILED);
    143 
    144        PKIX_CHECK(PKIX_PL_Object_Alloc
    145                    (PKIX_TARGETCERTCHECKERSTATE_TYPE,
    146                    sizeof (pkix_TargetCertCheckerState),
    147                    (PKIX_PL_Object **)&state,
    148                    plContext),
    149                    PKIX_COULDNOTCREATETARGETCERTCHECKERSTATEOBJECT);
    150 
    151        /* initialize fields */
    152 
    153        if (certSelector != NULL) {
    154 
    155                PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
    156                        (certSelector, &certSelectorParams, plContext),
    157                        PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMFAILED);
    158 
    159                if (certSelectorParams != NULL) {
    160 
    161                        PKIX_CHECK(PKIX_ComCertSelParams_GetPathToNames
    162                            (certSelectorParams,
    163                            &pathToNameList,
    164                            plContext),
    165                            PKIX_COMCERTSELPARAMSGETPATHTONAMESFAILED);
    166 
    167                        PKIX_CHECK(PKIX_ComCertSelParams_GetExtendedKeyUsage
    168                            (certSelectorParams,
    169                            &extKeyUsageList,
    170                            plContext),
    171                            PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED);
    172 
    173                        PKIX_CHECK(PKIX_ComCertSelParams_GetSubjAltNames
    174                            (certSelectorParams,
    175                            &subjAltNameList,
    176                            plContext),
    177                            PKIX_COMCERTSELPARAMSGETSUBJALTNAMESFAILED);
    178 
    179                        PKIX_CHECK(PKIX_ComCertSelParams_GetMatchAllSubjAltNames
    180                            (certSelectorParams,
    181                            &subjAltNameMatchAll,
    182                            plContext),
    183                            PKIX_COMCERTSELPARAMSGETSUBJALTNAMESFAILED);
    184                }
    185        }
    186 
    187        state->certsRemaining = certsRemaining;
    188        state->subjAltNameMatchAll = subjAltNameMatchAll;
    189 
    190        PKIX_INCREF(certSelector);
    191        state->certSelector = certSelector;
    192 
    193        state->pathToNameList = pathToNameList;
    194        pathToNameList = NULL;
    195 
    196        state->extKeyUsageList = extKeyUsageList;
    197        extKeyUsageList = NULL;
    198 
    199        state->subjAltNameList = subjAltNameList;
    200        subjAltNameList = NULL;
    201 
    202        state->extKeyUsageOID = extKeyUsageOID;
    203        extKeyUsageOID = NULL;
    204 
    205        state->subjAltNameOID = subjAltNameOID;
    206        subjAltNameOID = NULL;
    207 
    208        *pState = state;
    209        state = NULL;
    210 
    211 cleanup:
    212        
    213        PKIX_DECREF(extKeyUsageOID);
    214        PKIX_DECREF(subjAltNameOID);
    215        PKIX_DECREF(pathToNameList);
    216        PKIX_DECREF(extKeyUsageList);
    217        PKIX_DECREF(subjAltNameList);
    218        PKIX_DECREF(state);
    219 
    220        PKIX_DECREF(certSelectorParams);
    221 
    222        PKIX_RETURN(TARGETCERTCHECKERSTATE);
    223 
    224 }
    225 
    226 /* --Private-TargetCertChecker-Functions------------------------------- */
    227 
    228 /*
    229 * FUNCTION: pkix_TargetCertChecker_Check
    230 * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h)
    231 */
    232 PKIX_Error *
    233 pkix_TargetCertChecker_Check(
    234        PKIX_CertChainChecker *checker,
    235        PKIX_PL_Cert *cert,
    236        PKIX_List *unresolvedCriticalExtensions,
    237        void **pNBIOContext,
    238        void *plContext)
    239 {
    240        pkix_TargetCertCheckerState *state = NULL;
    241        PKIX_CertSelector_MatchCallback certSelectorMatch = NULL;
    242        PKIX_PL_CertNameConstraints *nameConstraints = NULL;
    243        PKIX_List *certSubjAltNames = NULL;
    244        PKIX_List *certExtKeyUsageList = NULL;
    245        PKIX_PL_GeneralName *name = NULL;
    246        PKIX_PL_X500Name *certSubjectName = NULL;
    247        PKIX_Boolean checkPassed = PKIX_FALSE;
    248        PKIX_UInt32 numItems, i;
    249        PKIX_UInt32 matchCount = 0;
    250 
    251        PKIX_ENTER(CERTCHAINCHECKER, "pkix_TargetCertChecker_Check");
    252        PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext);
    253 
    254        *pNBIOContext = NULL; /* we never block on pending I/O */
    255 
    256        PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState
    257                    (checker, (PKIX_PL_Object **)&state, plContext),
    258                    PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED);
    259 
    260        (state->certsRemaining)--;
    261 
    262        if (state->pathToNameList != NULL) {
    263 
    264                PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints
    265                    (cert, &nameConstraints, plContext),
    266                    PKIX_CERTGETNAMECONSTRAINTSFAILED);
    267 
    268                /*
    269                 * XXX We should either make the following call a public one
    270                 * so it is legal to call from the portability layer or we
    271                 * should try to create pathToNameList as CertNameConstraints
    272                 * then call the existing check function.
    273                 */
    274                PKIX_CHECK(PKIX_PL_CertNameConstraints_CheckNamesInNameSpace
    275                    (state->pathToNameList,
    276                    nameConstraints,
    277                    &checkPassed,
    278                    plContext),
    279                    PKIX_CERTNAMECONSTRAINTSCHECKNAMEINNAMESPACEFAILED);
    280 
    281                if (checkPassed != PKIX_TRUE) {
    282                    PKIX_ERROR(PKIX_VALIDATIONFAILEDPATHTONAMECHECKFAILED);
    283                }
    284 
    285        }
    286 
    287        PKIX_CHECK(PKIX_PL_Cert_GetSubjectAltNames
    288                    (cert, &certSubjAltNames, plContext),
    289                    PKIX_CERTGETSUBJALTNAMESFAILED);
    290 
    291        if (state->subjAltNameList != NULL && certSubjAltNames != NULL) {
    292 
    293                PKIX_CHECK(PKIX_List_GetLength
    294                        (state->subjAltNameList, &numItems, plContext),
    295                        PKIX_LISTGETLENGTHFAILED);
    296 
    297                for (i = 0; i < numItems; i++) {
    298 
    299                        PKIX_CHECK(PKIX_List_GetItem
    300                            (state->subjAltNameList,
    301                            i,
    302                            (PKIX_PL_Object **) &name,
    303                            plContext),
    304                            PKIX_LISTGETITEMFAILED);
    305 
    306                        PKIX_CHECK(pkix_List_Contains
    307                            (certSubjAltNames,
    308                            (PKIX_PL_Object *) name,
    309                            &checkPassed,
    310                            plContext),
    311                            PKIX_LISTCONTAINSFAILED);
    312 
    313                        PKIX_DECREF(name);
    314 
    315                        if (checkPassed == PKIX_TRUE) {
    316 
    317                            if (state->subjAltNameMatchAll == PKIX_FALSE) {
    318                                matchCount = numItems;
    319                                break;
    320                            } else {
    321                                /* else continue checking next */
    322                                matchCount++;
    323                            }
    324 
    325                        }
    326                }
    327 
    328                if (matchCount != numItems) {
    329                        PKIX_ERROR(PKIX_SUBJALTNAMECHECKFAILED);
    330 
    331                }
    332        }
    333 
    334        if (state->certsRemaining == 0) {
    335 
    336            if (state->certSelector != NULL) {
    337                PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
    338                           (state->certSelector,
    339                            &certSelectorMatch,
    340                            plContext),
    341                           PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
    342 
    343                PKIX_CHECK(certSelectorMatch
    344                           (state->certSelector,
    345                            cert,
    346                            plContext),
    347                           PKIX_CERTSELECTORMATCHFAILED);
    348            } else {
    349                /* Check at least cert/key usages if target cert selector
    350                 * is not set. */
    351                PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert,
    352                                         PKIX_FALSE  /* is chain cert*/,
    353                                         plContext),
    354                           PKIX_CERTVERIFYCERTTYPEFAILED);
    355            }
    356            /*
    357             * There are two Extended Key Usage Checkings
    358             * available :
    359             * 1) here at the targetcertchecker where we
    360             *    verify the Extended Key Usage OIDs application
    361             *    specifies via ComCertSelParams are included
    362             *    in Cert's Extended Key Usage OID's. Note,
    363             *    this is an OID to OID comparison and only last
    364             *    Cert is checked.
    365             * 2) at user defined ekuchecker where checking
    366             *    is applied to all Certs on the chain and
    367             *    the NSS Extended Key Usage algorithm is
    368             *    used. In order to invoke this checking, not
    369             *    only does the ComCertSelparams needs to be
    370             *    set, the EKU initialize call is required to
    371             *    activate the checking.
    372             *
    373             * XXX We use the same ComCertSelParams Set/Get
    374             * functions to set the parameters for both cases.
    375             * We may want to separate them in the future.
    376             */
    377            
    378            PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage
    379                       (cert, &certExtKeyUsageList, plContext),
    380                       PKIX_CERTGETEXTENDEDKEYUSAGEFAILED);
    381            
    382            
    383            if (state->extKeyUsageList != NULL &&
    384                certExtKeyUsageList != NULL) {
    385                
    386                PKIX_CHECK(PKIX_List_GetLength
    387                           (state->extKeyUsageList, &numItems, plContext),
    388                           PKIX_LISTGETLENGTHFAILED);
    389                
    390                for (i = 0; i < numItems; i++) {
    391                    
    392                    PKIX_CHECK(PKIX_List_GetItem
    393                               (state->extKeyUsageList,
    394                                i,
    395                                (PKIX_PL_Object **) &name,
    396                                plContext),
    397                               PKIX_LISTGETITEMFAILED);
    398                    
    399                    PKIX_CHECK(pkix_List_Contains
    400                               (certExtKeyUsageList,
    401                                (PKIX_PL_Object *) name,
    402                                &checkPassed,
    403                                plContext),
    404                               PKIX_LISTCONTAINSFAILED);
    405                    
    406                    PKIX_DECREF(name);
    407                    
    408                    if (checkPassed != PKIX_TRUE) {
    409                        PKIX_ERROR
    410                            (PKIX_EXTENDEDKEYUSAGECHECKINGFAILED);
    411                        
    412                    }
    413                }
    414            }
    415        } else {
    416            /* Check key usage and cert type based on certificate usage. */
    417            PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert, PKIX_TRUE,
    418                                                         plContext),
    419                       PKIX_CERTVERIFYCERTTYPEFAILED);
    420        }
    421 
    422        /* Remove Critical Extension OID from list */
    423        if (unresolvedCriticalExtensions != NULL) {
    424 
    425                PKIX_CHECK(pkix_List_Remove
    426                            (unresolvedCriticalExtensions,
    427                            (PKIX_PL_Object *) state->extKeyUsageOID,
    428                            plContext),
    429                            PKIX_LISTREMOVEFAILED);
    430 
    431                PKIX_CHECK(PKIX_PL_Cert_GetSubject
    432                            (cert, &certSubjectName, plContext),
    433                            PKIX_CERTGETSUBJECTFAILED);
    434 
    435                if (certSubjAltNames != NULL) {
    436                        PKIX_CHECK(pkix_List_Remove
    437                            (unresolvedCriticalExtensions,
    438                            (PKIX_PL_Object *) state->subjAltNameOID,
    439                            plContext),
    440                            PKIX_LISTREMOVEFAILED);
    441                }
    442 
    443        }
    444 
    445 cleanup:
    446 
    447        PKIX_DECREF(name);
    448        PKIX_DECREF(nameConstraints);
    449        PKIX_DECREF(certSubjAltNames);
    450        PKIX_DECREF(certExtKeyUsageList);
    451        PKIX_DECREF(certSubjectName);
    452        PKIX_DECREF(state);
    453 
    454        PKIX_RETURN(CERTCHAINCHECKER);
    455 
    456 }
    457 
    458 /*
    459 * FUNCTION: pkix_TargetCertChecker_Initialize
    460 * DESCRIPTION:
    461 *
    462 *  Creates a new CertChainChecker and stores it at "pChecker", where it will
    463 *  used by pkix_TargetCertChecker_Check to check that the final certificate
    464 *  of a chain meets the criteria of the CertSelector pointed to by
    465 *  "certSelector". The number of certs remaining in the chain, represented by
    466 *  "certsRemaining" is used to initialize the checker's state.
    467 *
    468 * PARAMETERS:
    469 *  "certSelector"
    470 *      Address of CertSelector representing the criteria against which the
    471 *      final certificate in a chain is to be matched. May be NULL.
    472 *  "certsRemaining"
    473 *      Number of certificates remaining in the chain.
    474 *  "pChecker"
    475 *      Address where object pointer will be stored. Must be non-NULL.
    476 *  "plContext"
    477 *      Platform-specific context pointer.
    478 * THREAD SAFETY:
    479 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    480 * RETURNS:
    481 *  Returns NULL if the function succeeds.
    482 *  Returns a CertChainChecker Error if the function fails in a non-fatal way.
    483 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    484 */
    485 PKIX_Error *
    486 pkix_TargetCertChecker_Initialize(
    487        PKIX_CertSelector *certSelector,
    488        PKIX_UInt32 certsRemaining,
    489        PKIX_CertChainChecker **pChecker,
    490        void *plContext)
    491 {
    492        pkix_TargetCertCheckerState *state = NULL;
    493 
    494        PKIX_ENTER(CERTCHAINCHECKER, "pkix_TargetCertChecker_Initialize");
    495        PKIX_NULLCHECK_ONE(pChecker);
    496 
    497        PKIX_CHECK(pkix_TargetCertCheckerState_Create
    498                    (certSelector, certsRemaining, &state, plContext),
    499                    PKIX_TARGETCERTCHECKERSTATECREATEFAILED);
    500 
    501        PKIX_CHECK(PKIX_CertChainChecker_Create
    502                    (pkix_TargetCertChecker_Check,
    503                    PKIX_FALSE,
    504                    PKIX_FALSE,
    505                    NULL,
    506                    (PKIX_PL_Object *)state,
    507                    pChecker,
    508                    plContext),
    509                    PKIX_CERTCHAINCHECKERCREATEFAILED);
    510 
    511 cleanup:
    512 
    513        PKIX_DECREF(state);
    514 
    515        PKIX_RETURN(CERTCHAINCHECKER);
    516 }