tor-browser

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

cmsutil.c (10940B)


      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 * CMS miscellaneous utility functions.
      7 */
      8 
      9 #include "cmslocal.h"
     10 
     11 #include "cert.h"
     12 #include "keyhi.h"
     13 #include "secasn1.h"
     14 #include "secitem.h"
     15 #include "secoid.h"
     16 #include "pk11func.h"
     17 #include "secerr.h"
     18 #include "sechash.h"
     19 
     20 /*
     21 * NSS_CMSArray_SortByDER - sort array of objects by objects' DER encoding
     22 *
     23 * make sure that the order of the objects guarantees valid DER (which must be
     24 * in lexigraphically ascending order for a SET OF); if reordering is necessary it
     25 * will be done in place (in objs).
     26 */
     27 SECStatus
     28 NSS_CMSArray_SortByDER(void **objs, const SEC_ASN1Template *objtemplate, void **objs2)
     29 {
     30    PLArenaPool *poolp;
     31    int num_objs;
     32    SECItem **enc_objs;
     33    SECStatus rv = SECFailure;
     34    int i;
     35 
     36    if (objs == NULL) /* already sorted */
     37        return SECSuccess;
     38 
     39    num_objs = NSS_CMSArray_Count((void **)objs);
     40    if (num_objs == 0 || num_objs == 1) /* already sorted. */
     41        return SECSuccess;
     42 
     43    poolp = PORT_NewArena(1024); /* arena for temporaries */
     44    if (poolp == NULL)
     45        return SECFailure; /* no memory; nothing we can do... */
     46 
     47    /*
     48     * Allocate arrays to hold the individual encodings which we will use
     49     * for comparisons and the reordered attributes as they are sorted.
     50     */
     51    enc_objs = (SECItem **)PORT_ArenaZAlloc(poolp, (num_objs + 1) * sizeof(SECItem *));
     52    if (enc_objs == NULL)
     53        goto loser;
     54 
     55    /* DER encode each individual object. */
     56    for (i = 0; i < num_objs; i++) {
     57        enc_objs[i] = SEC_ASN1EncodeItem(poolp, NULL, objs[i], objtemplate);
     58        if (enc_objs[i] == NULL)
     59            goto loser;
     60    }
     61    enc_objs[num_objs] = NULL;
     62 
     63    /* now compare and sort objs by the order of enc_objs */
     64    NSS_CMSArray_Sort((void **)enc_objs, NSS_CMSUtil_DERCompare, objs, objs2);
     65 
     66    rv = SECSuccess;
     67 
     68 loser:
     69    PORT_FreeArena(poolp, PR_FALSE);
     70    return rv;
     71 }
     72 
     73 /*
     74 * NSS_CMSUtil_DERCompare - for use with NSS_CMSArray_Sort to
     75 *  sort arrays of SECItems containing DER
     76 */
     77 int
     78 NSS_CMSUtil_DERCompare(void *a, void *b)
     79 {
     80    SECItem *der1 = (SECItem *)a;
     81    SECItem *der2 = (SECItem *)b;
     82    unsigned int j;
     83 
     84    /*
     85     * Find the lowest (lexigraphically) encoding.  One that is
     86     * shorter than all the rest is known to be "less" because each
     87     * attribute is of the same type (a SEQUENCE) and so thus the
     88     * first octet of each is the same, and the second octet is
     89     * the length (or the length of the length with the high bit
     90     * set, followed by the length, which also works out to always
     91     * order the shorter first).  Two (or more) that have the
     92     * same length need to be compared byte by byte until a mismatch
     93     * is found.
     94     */
     95    if (der1->len != der2->len)
     96        return (der1->len < der2->len) ? -1 : 1;
     97 
     98    for (j = 0; j < der1->len; j++) {
     99        if (der1->data[j] == der2->data[j])
    100            continue;
    101        return (der1->data[j] < der2->data[j]) ? -1 : 1;
    102    }
    103    return 0;
    104 }
    105 
    106 /*
    107 * NSS_CMSAlgArray_GetIndexByAlgID - find a specific algorithm in an array of
    108 * algorithms.
    109 *
    110 * algorithmArray - array of algorithm IDs
    111 * algid - algorithmid of algorithm to pick
    112 *
    113 * Returns:
    114 *  An integer containing the index of the algorithm in the array or -1 if
    115 *  algorithm was not found.
    116 */
    117 int
    118 NSS_CMSAlgArray_GetIndexByAlgID(SECAlgorithmID **algorithmArray, SECAlgorithmID *algid)
    119 {
    120    int i;
    121 
    122    if (algorithmArray == NULL || algorithmArray[0] == NULL)
    123        return -1;
    124 
    125    for (i = 0; algorithmArray[i] != NULL; i++) {
    126        if (SECOID_CompareAlgorithmID(algorithmArray[i], algid) == SECEqual)
    127            break; /* bingo */
    128    }
    129 
    130    if (algorithmArray[i] == NULL)
    131        return -1; /* not found */
    132 
    133    return i;
    134 }
    135 
    136 /*
    137 * NSS_CMSAlgArray_GetIndexByAlgTag - find a specific algorithm in an array of
    138 * algorithms.
    139 *
    140 * algorithmArray - array of algorithm IDs
    141 * algtag - algorithm tag of algorithm to pick
    142 *
    143 * Returns:
    144 *  An integer containing the index of the algorithm in the array or -1 if
    145 *  algorithm was not found.
    146 */
    147 int
    148 NSS_CMSAlgArray_GetIndexByAlgTag(SECAlgorithmID **algorithmArray,
    149                                 SECOidTag algtag)
    150 {
    151    SECOidData *algid;
    152    int i = -1;
    153 
    154    if (algorithmArray == NULL || algorithmArray[0] == NULL)
    155        return i;
    156 
    157 #ifdef ORDER_N_SQUARED
    158    for (i = 0; algorithmArray[i] != NULL; i++) {
    159        algid = SECOID_FindOID(&(algorithmArray[i]->algorithm));
    160        if (algid->offset == algtag)
    161            break; /* bingo */
    162    }
    163 #else
    164    algid = SECOID_FindOIDByTag(algtag);
    165    if (!algid)
    166        return i;
    167    for (i = 0; algorithmArray[i] != NULL; i++) {
    168        if (SECITEM_ItemsAreEqual(&algorithmArray[i]->algorithm, &algid->oid))
    169            break; /* bingo */
    170    }
    171 #endif
    172 
    173    if (algorithmArray[i] == NULL)
    174        return -1; /* not found */
    175 
    176    return i;
    177 }
    178 
    179 /*
    180 * Map a sign algorithm to a digest algorithm.
    181 * This is used to handle incorrectly formatted packages sent to us
    182 * from Windows 2003.
    183 */
    184 SECOidTag
    185 NSS_CMSUtil_MapSignAlgs(SECOidTag signAlg)
    186 {
    187    switch (signAlg) {
    188        case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
    189            return SEC_OID_MD2;
    190            break;
    191        case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
    192            return SEC_OID_MD5;
    193            break;
    194        case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
    195        case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
    196        case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
    197            return SEC_OID_SHA1;
    198            break;
    199        case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
    200        case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
    201            return SEC_OID_SHA256;
    202            break;
    203        case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
    204        case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
    205            return SEC_OID_SHA384;
    206            break;
    207        case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
    208        case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
    209            return SEC_OID_SHA512;
    210            break;
    211        default:
    212            break;
    213    }
    214    /* not one of the algtags incorrectly sent to us*/
    215    return signAlg;
    216 }
    217 
    218 const SECHashObject *
    219 NSS_CMSUtil_GetHashObjByAlgID(SECAlgorithmID *algid)
    220 {
    221    SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm));
    222    const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag);
    223 
    224    return digobj;
    225 }
    226 
    227 const SEC_ASN1Template *
    228 NSS_CMSUtil_GetTemplateByTypeTag(SECOidTag type)
    229 {
    230    const SEC_ASN1Template *template;
    231    extern const SEC_ASN1Template NSSCMSSignedDataTemplate[];
    232    extern const SEC_ASN1Template NSSCMSEnvelopedDataTemplate[];
    233    extern const SEC_ASN1Template NSSCMSEncryptedDataTemplate[];
    234    extern const SEC_ASN1Template NSSCMSDigestedDataTemplate[];
    235 
    236    switch (type) {
    237        case SEC_OID_PKCS7_SIGNED_DATA:
    238            template = NSSCMSSignedDataTemplate;
    239            break;
    240        case SEC_OID_PKCS7_ENVELOPED_DATA:
    241            template = NSSCMSEnvelopedDataTemplate;
    242            break;
    243        case SEC_OID_PKCS7_ENCRYPTED_DATA:
    244            template = NSSCMSEncryptedDataTemplate;
    245            break;
    246        case SEC_OID_PKCS7_DIGESTED_DATA:
    247            template = NSSCMSDigestedDataTemplate;
    248            break;
    249        default:
    250            template = NSS_CMSType_GetTemplate(type);
    251            break;
    252    }
    253    return template;
    254 }
    255 
    256 size_t
    257 NSS_CMSUtil_GetSizeByTypeTag(SECOidTag type)
    258 {
    259    size_t size;
    260 
    261    switch (type) {
    262        case SEC_OID_PKCS7_SIGNED_DATA:
    263            size = sizeof(NSSCMSSignedData);
    264            break;
    265        case SEC_OID_PKCS7_ENVELOPED_DATA:
    266            size = sizeof(NSSCMSEnvelopedData);
    267            break;
    268        case SEC_OID_PKCS7_ENCRYPTED_DATA:
    269            size = sizeof(NSSCMSEncryptedData);
    270            break;
    271        case SEC_OID_PKCS7_DIGESTED_DATA:
    272            size = sizeof(NSSCMSDigestedData);
    273            break;
    274        default:
    275            size = NSS_CMSType_GetContentSize(type);
    276            break;
    277    }
    278    return size;
    279 }
    280 
    281 NSSCMSContentInfo *
    282 NSS_CMSContent_GetContentInfo(void *msg, SECOidTag type)
    283 {
    284    NSSCMSContent c;
    285    NSSCMSContentInfo *cinfo = NULL;
    286 
    287    if (!msg)
    288        return cinfo;
    289    c.pointer = msg;
    290    switch (type) {
    291        case SEC_OID_PKCS7_SIGNED_DATA:
    292            cinfo = &(c.signedData->contentInfo);
    293            break;
    294        case SEC_OID_PKCS7_ENVELOPED_DATA:
    295            cinfo = &(c.envelopedData->contentInfo);
    296            break;
    297        case SEC_OID_PKCS7_ENCRYPTED_DATA:
    298            cinfo = &(c.encryptedData->contentInfo);
    299            break;
    300        case SEC_OID_PKCS7_DIGESTED_DATA:
    301            cinfo = &(c.digestedData->contentInfo);
    302            break;
    303        default:
    304            cinfo = NULL;
    305            if (NSS_CMSType_IsWrapper(type)) {
    306                cinfo = &(c.genericData->contentInfo);
    307            }
    308    }
    309    /* We are using a union as a form of 'safe casting'. This
    310     * syntax confuses cppcheck, so tell it it's OK (and any human
    311     * who happens along to verify any other scanner warnings) */
    312    /* cppcheck-suppress returnDanglingLifetime */
    313    return cinfo;
    314 }
    315 
    316 const char *
    317 NSS_CMSUtil_VerificationStatusToString(NSSCMSVerificationStatus vs)
    318 {
    319    switch (vs) {
    320        case NSSCMSVS_Unverified:
    321            return "Unverified";
    322        case NSSCMSVS_GoodSignature:
    323            return "GoodSignature";
    324        case NSSCMSVS_BadSignature:
    325            return "BadSignature";
    326        case NSSCMSVS_DigestMismatch:
    327            return "DigestMismatch";
    328        case NSSCMSVS_SigningCertNotFound:
    329            return "SigningCertNotFound";
    330        case NSSCMSVS_SigningCertNotTrusted:
    331            return "SigningCertNotTrusted";
    332        case NSSCMSVS_SignatureAlgorithmUnknown:
    333            return "SignatureAlgorithmUnknown";
    334        case NSSCMSVS_SignatureAlgorithmUnsupported:
    335            return "SignatureAlgorithmUnsupported";
    336        case NSSCMSVS_MalformedSignature:
    337            return "MalformedSignature";
    338        case NSSCMSVS_ProcessingError:
    339            return "ProcessingError";
    340        default:
    341            return "Unknown";
    342    }
    343 }
    344 
    345 SECStatus
    346 NSS_CMSDEREncode(NSSCMSMessage *cmsg, SECItem *input, SECItem *derOut,
    347                 PLArenaPool *arena)
    348 {
    349    NSSCMSEncoderContext *ecx;
    350    SECStatus rv = SECSuccess;
    351    if (!cmsg || !derOut || !arena) {
    352        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    353        return SECFailure;
    354    }
    355    ecx = NSS_CMSEncoder_Start(cmsg, 0, 0, derOut, arena, 0, 0, 0, 0, 0, 0);
    356    if (!ecx) {
    357        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    358        return SECFailure;
    359    }
    360    if (input) {
    361        rv = NSS_CMSEncoder_Update(ecx, (const char *)input->data, input->len);
    362        if (rv) {
    363            PORT_SetError(SEC_ERROR_BAD_DATA);
    364        }
    365    }
    366    rv |= NSS_CMSEncoder_Finish(ecx);
    367    if (rv) {
    368        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    369    }
    370    return rv;
    371 }