tor-browser

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

pppolicy.c (8087B)


      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 /*
      6 * Support for various policy related extensions
      7 */
      8 
      9 #include "seccomon.h"
     10 #include "secport.h"
     11 #include "secder.h"
     12 #include "cert.h"
     13 #include "secoid.h"
     14 #include "secasn1.h"
     15 #include "secerr.h"
     16 #include "nspr.h"
     17 #include "secutil.h"
     18 
     19 /* This implementation is derived from the one in nss/lib/certdb/policyxtn.c .
     20 ** The chief difference is the addition of the OPTIONAL flag to many
     21 ** parts.  The idea is to be able to parse and print as much of the
     22 ** policy extension as possible, even if some parts are invalid.
     23 **
     24 ** If this approach still is unable to decode policy extensions that
     25 ** contain invalid parts, then the next approach will be to parse
     26 ** the PolicyInfos as a SEQUENCE of ANYs, and then parse each of them
     27 ** as PolicyInfos, with the PolicyQualifiers being ANYs, and finally
     28 ** parse each of the PolicyQualifiers.
     29 */
     30 
     31 static const SEC_ASN1Template secu_PolicyQualifierTemplate[] = {
     32    { SEC_ASN1_SEQUENCE,
     33      0, NULL, sizeof(CERTPolicyQualifier) },
     34    { SEC_ASN1_OBJECT_ID,
     35      offsetof(CERTPolicyQualifier, qualifierID) },
     36    { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL,
     37      offsetof(CERTPolicyQualifier, qualifierValue) },
     38    { 0 }
     39 };
     40 
     41 static const SEC_ASN1Template secu_PolicyInfoTemplate[] = {
     42    { SEC_ASN1_SEQUENCE,
     43      0, NULL, sizeof(CERTPolicyInfo) },
     44    { SEC_ASN1_OBJECT_ID,
     45      offsetof(CERTPolicyInfo, policyID) },
     46    { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_OPTIONAL,
     47      offsetof(CERTPolicyInfo, policyQualifiers),
     48      secu_PolicyQualifierTemplate },
     49    { 0 }
     50 };
     51 
     52 static const SEC_ASN1Template secu_CertificatePoliciesTemplate[] = {
     53    { SEC_ASN1_SEQUENCE_OF,
     54      offsetof(CERTCertificatePolicies, policyInfos),
     55      secu_PolicyInfoTemplate, sizeof(CERTCertificatePolicies) }
     56 };
     57 
     58 static CERTCertificatePolicies *
     59 secu_DecodeCertificatePoliciesExtension(SECItem *extnValue)
     60 {
     61    PLArenaPool *arena = NULL;
     62    SECStatus rv;
     63    CERTCertificatePolicies *policies;
     64    CERTPolicyInfo **policyInfos, *policyInfo;
     65    CERTPolicyQualifier **policyQualifiers, *policyQualifier;
     66    SECItem newExtnValue;
     67 
     68    /* make a new arena */
     69    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     70 
     71    if (!arena) {
     72        goto loser;
     73    }
     74 
     75    /* allocate the certifiate policies structure */
     76    policies = PORT_ArenaZNew(arena, CERTCertificatePolicies);
     77    if (policies == NULL) {
     78        goto loser;
     79    }
     80 
     81    policies->arena = arena;
     82 
     83    /* copy the DER into the arena, since Quick DER returns data that points
     84       into the DER input, which may get freed by the caller */
     85    rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue);
     86    if (rv != SECSuccess) {
     87        goto loser;
     88    }
     89 
     90    /* decode the policy info */
     91    rv = SEC_QuickDERDecodeItem(arena, policies,
     92                                secu_CertificatePoliciesTemplate,
     93                                &newExtnValue);
     94 
     95    if (rv != SECSuccess) {
     96        goto loser;
     97    }
     98 
     99    /* initialize the oid tags */
    100    policyInfos = policies->policyInfos;
    101    while (policyInfos != NULL && *policyInfos != NULL) {
    102        policyInfo = *policyInfos;
    103        policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID);
    104        policyQualifiers = policyInfo->policyQualifiers;
    105        while (policyQualifiers && *policyQualifiers != NULL) {
    106            policyQualifier = *policyQualifiers;
    107            policyQualifier->oid =
    108                SECOID_FindOIDTag(&policyQualifier->qualifierID);
    109            policyQualifiers++;
    110        }
    111        policyInfos++;
    112    }
    113 
    114    return (policies);
    115 
    116 loser:
    117    if (arena != NULL) {
    118        PORT_FreeArena(arena, PR_FALSE);
    119    }
    120 
    121    return (NULL);
    122 }
    123 
    124 static char *
    125 itemToString(SECItem *item)
    126 {
    127    char *string;
    128 
    129    string = PORT_ZAlloc(item->len + 1);
    130    if (string == NULL)
    131        return NULL;
    132    PORT_Memcpy(string, item->data, item->len);
    133    string[item->len] = 0;
    134    return string;
    135 }
    136 
    137 static SECStatus
    138 secu_PrintUserNoticeQualifier(FILE *out, SECItem *qualifierValue,
    139                              char *msg, int level)
    140 {
    141    CERTUserNotice *userNotice = NULL;
    142    if (qualifierValue)
    143        userNotice = CERT_DecodeUserNotice(qualifierValue);
    144    if (userNotice) {
    145        if (userNotice->noticeReference.organization.len != 0) {
    146            char *string =
    147                itemToString(&userNotice->noticeReference.organization);
    148            SECItem **itemList = userNotice->noticeReference.noticeNumbers;
    149 
    150            while (itemList && *itemList) {
    151                SECU_PrintInteger(out, *itemList, string, level + 1);
    152                itemList++;
    153            }
    154            PORT_Free(string);
    155        }
    156        if (userNotice->displayText.len != 0) {
    157            SECU_PrintString(out, &userNotice->displayText,
    158                             "Display Text", level + 1);
    159        }
    160        CERT_DestroyUserNotice(userNotice);
    161        return SECSuccess;
    162    }
    163    return SECFailure; /* caller will print this value */
    164 }
    165 
    166 static SECStatus
    167 secu_PrintPolicyQualifier(FILE *out, CERTPolicyQualifier *policyQualifier,
    168                          char *msg, int level)
    169 {
    170    SECStatus rv;
    171    SECItem *qualifierValue = &policyQualifier->qualifierValue;
    172 
    173    SECU_PrintObjectID(out, &policyQualifier->qualifierID,
    174                       "Policy Qualifier Name", level);
    175    if (!qualifierValue->data) {
    176        SECU_Indent(out, level);
    177        fprintf(out, "Error: missing qualifier\n");
    178    } else
    179        switch (policyQualifier->oid) {
    180            case SEC_OID_PKIX_USER_NOTICE_QUALIFIER:
    181                rv = secu_PrintUserNoticeQualifier(out, qualifierValue, msg, level);
    182                if (SECSuccess == rv)
    183                    break;
    184            /* fall through on error */
    185            case SEC_OID_PKIX_CPS_POINTER_QUALIFIER:
    186            default:
    187                SECU_PrintAny(out, qualifierValue, "Policy Qualifier Data", level);
    188                break;
    189        }
    190    return SECSuccess;
    191 }
    192 
    193 static SECStatus
    194 secu_PrintPolicyInfo(FILE *out, CERTPolicyInfo *policyInfo, char *msg, int level)
    195 {
    196    CERTPolicyQualifier **policyQualifiers;
    197 
    198    policyQualifiers = policyInfo->policyQualifiers;
    199    SECU_PrintObjectID(out, &policyInfo->policyID, "Policy Name", level);
    200 
    201    while (policyQualifiers && *policyQualifiers != NULL) {
    202        secu_PrintPolicyQualifier(out, *policyQualifiers, "", level + 1);
    203        policyQualifiers++;
    204    }
    205    return SECSuccess;
    206 }
    207 
    208 void
    209 SECU_PrintPolicy(FILE *out, SECItem *value, char *msg, int level)
    210 {
    211    CERTCertificatePolicies *policies = NULL;
    212    CERTPolicyInfo **policyInfos;
    213 
    214    if (msg) {
    215        SECU_Indent(out, level);
    216        fprintf(out, "%s: \n", msg);
    217        level++;
    218    }
    219    policies = secu_DecodeCertificatePoliciesExtension(value);
    220    if (policies == NULL) {
    221        SECU_PrintAny(out, value, "Invalid Policy Data", level);
    222        return;
    223    }
    224 
    225    policyInfos = policies->policyInfos;
    226    while (policyInfos && *policyInfos != NULL) {
    227        secu_PrintPolicyInfo(out, *policyInfos, "", level);
    228        policyInfos++;
    229    }
    230 
    231    CERT_DestroyCertificatePoliciesExtension(policies);
    232 }
    233 
    234 void
    235 SECU_PrintPrivKeyUsagePeriodExtension(FILE *out, SECItem *value,
    236                                      char *msg, int level)
    237 {
    238    CERTPrivKeyUsagePeriod *prd;
    239    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    240 
    241    if (!arena) {
    242        goto loser;
    243    }
    244    prd = CERT_DecodePrivKeyUsagePeriodExtension(arena, value);
    245    if (!prd) {
    246        goto loser;
    247    }
    248    if (prd->notBefore.data) {
    249        SECU_PrintGeneralizedTime(out, &prd->notBefore, "Not Before", level);
    250    }
    251    if (prd->notAfter.data) {
    252        SECU_PrintGeneralizedTime(out, &prd->notAfter, "Not After ", level);
    253    }
    254    if (!prd->notBefore.data && !prd->notAfter.data) {
    255        SECU_Indent(out, level);
    256        fprintf(out, "Error: notBefore or notAfter MUST be present.\n");
    257    loser:
    258        SECU_PrintAny(out, value, msg, level);
    259    }
    260    if (arena) {
    261        PORT_FreeArena(arena, PR_FALSE);
    262    }
    263 }