tor-browser

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

validation.c (11695B)


      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 #ifdef _CRTDBG_MAP_ALLOC
      6 #include <stdlib.h>
      7 #include <crtdbg.h>
      8 #endif
      9 
     10 #include "nspr.h"
     11 #include "secutil.h"
     12 #include "pk11func.h"
     13 #include "nss.h"
     14 #include "secport.h"
     15 #include "secpkcs5.h"
     16 #include "sechash.h"
     17 #include "certdb.h"
     18 #include "secmod.h"
     19 
     20 static char *progName;
     21 PRBool debug = PR_FALSE;
     22 
     23 #define ERR_USAGE 2
     24 #define ERR_PK11GETSLOT 13
     25 
     26 static void
     27 Usage()
     28 {
     29 #define FPS PR_fprintf(PR_STDERR,
     30    FPS "Usage:	 %s [-d certdir] [-P dbprefix] [-h tokenname]\n",
     31 			 progName);
     32    FPS "\t\t [-k slotpwfile | -K slotpw] [-v][-o|-p]\n");
     33 
     34    exit(ERR_USAGE);
     35 }
     36 
     37 typedef enum {
     38    tagULong,
     39    tagULongFlag,
     40    tagVersion,
     41    tagUtf8,
     42    tagValidationAuthorityType,
     43    tagValidationType,
     44 } tagType;
     45 
     46 typedef struct {
     47    const char *attributeName;
     48    tagType attributeStorageType;
     49 } attributeTag;
     50 
     51 enum {
     52    opt_CertDir = 0,
     53    opt_TokenName,
     54    opt_SlotPWFile,
     55    opt_SlotPW,
     56    opt_DBPrefix,
     57    opt_Debug,
     58    /* we determine which validation objects we search for by
     59     * whether or not pkcs 11 v3.2 is available, These options
     60     * override the default */
     61    opt_ForceVendor,
     62    opt_ForcePKCS11,
     63 };
     64 
     65 static secuCommandFlag validation_options[] = {
     66    { /* opt_CertDir        */ 'd', PR_TRUE, 0, PR_FALSE },
     67    { /* opt_TokenName      */ 'h', PR_TRUE, 0, PR_FALSE },
     68    { /* opt_SlotPWFile     */ 'k', PR_TRUE, 0, PR_FALSE },
     69    { /* opt_SlotPW         */ 'K', PR_TRUE, 0, PR_FALSE },
     70    { /* opt_DBPrefix       */ 'P', PR_TRUE, 0, PR_FALSE },
     71    { /* opt_Debug          */ 'v', PR_FALSE, 0, PR_FALSE },
     72    { /* opt_ForceVendor    */ 'o', PR_FALSE, 0, PR_FALSE },
     73    { /* opt_ForcePKCS11    */ 'p', PR_FALSE, 0, PR_FALSE }
     74 };
     75 
     76 const char *validationAuthorityTable[] = {
     77    "Unspecified",
     78    "NIST/CMVP",
     79    "Common Criteria"
     80 };
     81 const size_t validationAuthorityTableSize = PR_ARRAY_SIZE(validationAuthorityTable);
     82 
     83 const char *validationTypeTable[] = {
     84    "Unspecified",
     85    "Software",
     86    "Hardware",
     87    "Firmware",
     88    "Hybrid",
     89 };
     90 const size_t validationTypeTableSize = PR_ARRAY_SIZE(validationTypeTable);
     91 
     92 void
     93 printULongTag(tagType tag, CK_ULONG value)
     94 {
     95    switch (tag) {
     96        case tagULongFlag:
     97            for (int i = 31; i >= 0; i--) {
     98                printf("%u", (unsigned int)(value >> i) & 0x1);
     99            }
    100            printf("\n");
    101            return; /* done */
    102        case tagValidationAuthorityType:
    103            if (value < validationAuthorityTableSize) {
    104                printf("%s\n", validationAuthorityTable[value]);
    105                return;
    106            }
    107            break; /* fall through to default */
    108        case tagValidationType:
    109            if (value < validationTypeTableSize) {
    110                printf("%s\n", validationTypeTable[value]);
    111                return;
    112            }
    113            break; /* fall through to default */
    114        default:
    115            break;
    116    }
    117    printf("%ld\n", value);
    118 }
    119 
    120 void
    121 dump_Raw(char *label, CK_ATTRIBUTE *attr)
    122 {
    123    int i;
    124    unsigned char *value = (unsigned char *)attr->pValue;
    125    printf("0x");
    126    for (i = 0; i < attr->ulValueLen; i++) {
    127        printf("%02x", value[i]);
    128    }
    129    printf("<%s>\n", label);
    130 }
    131 
    132 SECStatus
    133 dump_validations(CK_OBJECT_CLASS objc, CK_ATTRIBUTE *template, int count,
    134                 attributeTag *tags, PK11SlotInfo *slot)
    135 {
    136    PK11GenericObject *objs, *obj;
    137 
    138    objs = PK11_FindGenericObjects(slot, objc);
    139 
    140    for (obj = objs; obj != NULL; obj = PK11_GetNextGenericObject(obj)) {
    141        int i;
    142        printf("Validation Object:\n");
    143        PK11_ReadRawAttributes(NULL, PK11_TypeGeneric, obj, template, count);
    144        for (i = 0; i < count; i++) {
    145            CK_ULONG ulong;
    146            CK_VERSION version;
    147            int len = template[i].ulValueLen;
    148            printf("    %s: ", tags[i].attributeName);
    149            if (len < 0) {
    150                printf("<failed>\n");
    151            } else if (len == 0) {
    152                printf("<empty>\n");
    153            } else
    154                switch (tags[i].attributeStorageType) {
    155                    case tagULongFlag:
    156                    case tagValidationAuthorityType:
    157                    case tagValidationType:
    158                    case tagULong:
    159                        if (len != sizeof(CK_ULONG)) {
    160                            dump_Raw("bad ulong", &template[i]);
    161                            break;
    162                        }
    163                        ulong = *(CK_ULONG *)template[i].pValue;
    164                        printULongTag(tags[i].attributeStorageType, ulong);
    165                        break;
    166                    case tagVersion:
    167                        if (len != sizeof(CK_VERSION)) {
    168                            dump_Raw("bad version", &template[i]);
    169                            break;
    170                        }
    171                        version = *(CK_VERSION *)template[i].pValue;
    172                        printf("%d.%d\n", version.major, version.minor);
    173                        break;
    174                    case tagUtf8:
    175                        printf("%.*s\n", len, (char *)template[i].pValue);
    176                        break;
    177                    default:
    178                        dump_Raw("unknown tag", &template[i]);
    179                        break;
    180                }
    181            PORT_Free(template[i].pValue);
    182            template[i].pValue = NULL;
    183            template[i].ulValueLen = 0;
    184        }
    185    }
    186    PK11_DestroyGenericObjects(objs);
    187    return SECSuccess;
    188 }
    189 
    190 int
    191 main(int argc, char **argv)
    192 {
    193    secuPWData slotPw = { PW_NONE, NULL };
    194    secuPWData p12FilePw = { PW_NONE, NULL };
    195    PK11SlotInfo *slot = NULL;
    196    char *slotname = NULL;
    197    char *dbprefix = "";
    198    char *nssdir = NULL;
    199    SECStatus rv = SECFailure;
    200    secuCommand validation;
    201    int local_errno = 0;
    202 
    203    CK_ATTRIBUTE validation_template[] = {
    204        { CKA_VALIDATION_MODULE_ID, NULL, 0 },
    205        { CKA_VALIDATION_AUTHORITY_TYPE, NULL, 0 },
    206        { CKA_VALIDATION_TYPE, NULL, 0 },
    207        { CKA_VALIDATION_VERSION, NULL, 0 },
    208        { CKA_VALIDATION_LEVEL, NULL, 0 },
    209        { CKA_VALIDATION_FLAG, NULL, 0 },
    210        { CKA_VALIDATION_COUNTRY, NULL, 0 },
    211        { CKA_VALIDATION_CERTIFICATE_IDENTIFIER, NULL, 0 },
    212        { CKA_VALIDATION_CERTIFICATE_URI, NULL, 0 },
    213        { CKA_VALIDATION_PROFILE, NULL, 0 },
    214        { CKA_VALIDATION_VENDOR_URI, NULL, 0 },
    215    };
    216    attributeTag validation_tags[] = {
    217        { "Validation Module ID", tagUtf8 },
    218        { "Validation Authority Type", tagValidationAuthorityType },
    219        { "Validation Type", tagValidationType },
    220        { "Validation Version", tagVersion },
    221        { "Validation Level", tagULong },
    222        { "Validation Flag", tagULongFlag },
    223        { "Validation Country", tagUtf8 },
    224        { "Validation Certificate Identifier", tagUtf8 },
    225        { "Validation Certificate URI", tagUtf8 },
    226        { "Validation Certificate Profile", tagUtf8 },
    227        { "Validation Vendor URI", tagUtf8 },
    228    };
    229 
    230    CK_ATTRIBUTE nss_validation_template[] = {
    231        { CKA_NSS_VALIDATION_TYPE, NULL, 0 },
    232        { CKA_NSS_VALIDATION_VERSION, NULL, 0 },
    233        { CKA_NSS_VALIDATION_LEVEL, NULL, 0 },
    234        { CKA_NSS_VALIDATION_MODULE_ID, NULL, 0 }
    235    };
    236    attributeTag nss_validation_tags[] = {
    237        { "Validation Type", tagULong },
    238        { "Validation Version", tagVersion },
    239        { "Validation Level", tagULong },
    240        { "Validation Module ID", tagUtf8 },
    241    };
    242 
    243 #ifdef _CRTDBG_MAP_ALLOC
    244    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    245 #endif
    246 
    247    validation.numCommands = 0;
    248    validation.commands = 0;
    249    validation.numOptions = PR_ARRAY_SIZE(validation_options);
    250    validation.options = validation_options;
    251 
    252    progName = strrchr(argv[0], '/');
    253    progName = progName ? progName + 1 : argv[0];
    254 
    255    rv = SECU_ParseCommandLine(argc, argv, progName, &validation);
    256 
    257    if (rv != SECSuccess)
    258        Usage();
    259 
    260    if (validation.options[opt_ForceVendor].activated &&
    261        validation.options[opt_ForcePKCS11].activated) {
    262        fprintf(stderr, "-o and -p are mutually exclusive\n");
    263        Usage();
    264    }
    265 
    266    debug = validation.options[opt_Debug].activated;
    267 
    268    slotname = SECU_GetOptionArg(&validation, opt_TokenName);
    269 
    270    if (validation.options[opt_SlotPWFile].activated) {
    271        slotPw.source = PW_FROMFILE;
    272        slotPw.data = PORT_Strdup(validation.options[opt_SlotPWFile].arg);
    273    }
    274 
    275    if (validation.options[opt_SlotPW].activated) {
    276        slotPw.source = PW_PLAINTEXT;
    277        slotPw.data = PORT_Strdup(validation.options[opt_SlotPW].arg);
    278    }
    279 
    280    if (validation.options[opt_CertDir].activated) {
    281        nssdir = validation.options[opt_CertDir].arg;
    282    }
    283    if (validation.options[opt_DBPrefix].activated) {
    284        dbprefix = validation.options[opt_DBPrefix].arg;
    285    }
    286 
    287    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
    288    if (nssdir == NULL && NSS_NoDB_Init("") == SECSuccess) {
    289        rv = SECSuccess;
    290        /* if the system isn't already in FIPS mode, we need
    291         * to switch to FIPS mode */
    292        if (!PK11_IsFIPS()) {
    293            /* flip to FIPS mode */
    294            SECMODModule *module = SECMOD_GetInternalModule();
    295            rv = SECMOD_DeleteInternalModule(module->commonName);
    296        }
    297    } else if (nssdir != NULL) {
    298        rv = NSS_Initialize(nssdir, dbprefix, dbprefix, "secmod.db", 0);
    299    }
    300    if (rv != SECSuccess) {
    301        SECU_PrintPRandOSError(progName);
    302        local_errno = -1;
    303        goto done;
    304    }
    305 
    306    if (!slotname || PL_strcmp(slotname, "internal") == 0)
    307        slot = PK11_GetInternalKeySlot();
    308    else
    309        slot = PK11_FindSlotByName(slotname);
    310 
    311    if (!slot) {
    312        SECU_PrintError(progName, "Invalid slot \"%s\"",
    313                        slotname ? "internal" : slotname);
    314        local_errno = ERR_PK11GETSLOT;
    315        goto done;
    316    }
    317    if (validation.options[opt_ForceVendor].activated) {
    318        rv = dump_validations(CKO_NSS_VALIDATION,
    319                              nss_validation_template,
    320                              PR_ARRAY_SIZE(nss_validation_template),
    321                              nss_validation_tags,
    322                              slot);
    323    } else if (validation.options[opt_ForcePKCS11].activated) {
    324        rv = dump_validations(CKO_VALIDATION,
    325                              validation_template,
    326                              PR_ARRAY_SIZE(validation_template),
    327                              validation_tags,
    328                              slot);
    329    } else if (PK11_CheckPKCS11Version(slot, 3, 2, PR_FALSE) >= 0) {
    330        rv = dump_validations(CKO_VALIDATION,
    331                              validation_template,
    332                              PR_ARRAY_SIZE(validation_template),
    333                              validation_tags,
    334                              slot);
    335    } else {
    336        rv = dump_validations(CKO_NSS_VALIDATION,
    337                              nss_validation_template,
    338                              PR_ARRAY_SIZE(nss_validation_template),
    339                              nss_validation_tags,
    340                              slot);
    341    }
    342 
    343    if (rv != SECSuccess) {
    344        SECU_PrintPRandOSError(progName);
    345        local_errno = -1;
    346    }
    347 
    348 done:
    349    if (slotPw.data != NULL)
    350        PORT_ZFree(slotPw.data, PL_strlen(slotPw.data));
    351    if (p12FilePw.data != NULL)
    352        PORT_ZFree(p12FilePw.data, PL_strlen(p12FilePw.data));
    353    if (slotname) {
    354        PORT_Free(slotname);
    355    }
    356    if (slot)
    357        PK11_FreeSlot(slot);
    358    if (NSS_Shutdown() != SECSuccess) {
    359        local_errno = 1;
    360    }
    361    PL_ArenaFinish();
    362    PR_Cleanup();
    363    return local_errno;
    364 }