tor-browser

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

pkcs1sig.c (4863B)


      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 #include "pkcs1sig.h"
      7 #include "hasht.h"
      8 #include "secerr.h"
      9 #include "secasn1t.h"
     10 #include "secoid.h"
     11 
     12 typedef struct pkcs1PrefixStr pkcs1Prefix;
     13 struct pkcs1PrefixStr {
     14    unsigned int len;
     15    PRUint8 *data;
     16 };
     17 
     18 /* The value for SGN_PKCS1_DIGESTINFO_MAX_PREFIX_LEN_EXCLUDING_OID is based on
     19 * the possible prefix encodings as explained below.
     20 */
     21 #define MAX_PREFIX_LEN_EXCLUDING_OID 10
     22 
     23 static SECStatus
     24 encodePrefix(const SECOidData *hashOid, unsigned int digestLen,
     25             pkcs1Prefix *prefix, PRBool withParams)
     26 {
     27    /* with params coding is:
     28     *  Sequence (2 bytes) {
     29     *      Sequence (2 bytes) {
     30     *               Oid (2 bytes)  {
     31     *                   Oid value (derOid->oid.len)
     32     *               }
     33     *               NULL (2 bytes)
     34     *      }
     35     *      OCTECT (2 bytes);
     36     *
     37     * without params coding is:
     38     *  Sequence (2 bytes) {
     39     *      Sequence (2 bytes) {
     40     *               Oid (2 bytes)  {
     41     *                   Oid value (derOid->oid.len)
     42     *               }
     43     *      }
     44     *      OCTECT (2 bytes);
     45     */
     46 
     47    unsigned int innerSeqLen = 2 + hashOid->oid.len;
     48    unsigned int outerSeqLen = 2 + innerSeqLen + 2 + digestLen;
     49    unsigned int extra = 0;
     50 
     51    if (withParams) {
     52        innerSeqLen += 2;
     53        outerSeqLen += 2;
     54        extra = 2;
     55    }
     56 
     57    if (innerSeqLen >= 128 ||
     58        outerSeqLen >= 128 ||
     59        (outerSeqLen + 2 - digestLen) >
     60            (MAX_PREFIX_LEN_EXCLUDING_OID + hashOid->oid.len)) {
     61        /* this is actually a library failure, It shouldn't happen */
     62        PORT_SetError(SEC_ERROR_INVALID_ARGS);
     63        return SECFailure;
     64    }
     65 
     66    prefix->len = 6 + hashOid->oid.len + extra + 2;
     67    prefix->data = PORT_Alloc(prefix->len);
     68    if (!prefix->data) {
     69        PORT_SetError(SEC_ERROR_NO_MEMORY);
     70        return SECFailure;
     71    }
     72 
     73    prefix->data[0] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED;
     74    prefix->data[1] = outerSeqLen;
     75    prefix->data[2] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED;
     76    prefix->data[3] = innerSeqLen;
     77    prefix->data[4] = SEC_ASN1_OBJECT_ID;
     78    prefix->data[5] = hashOid->oid.len;
     79    PORT_Memcpy(&prefix->data[6], hashOid->oid.data, hashOid->oid.len);
     80    if (withParams) {
     81        prefix->data[6 + hashOid->oid.len] = SEC_ASN1_NULL;
     82        prefix->data[6 + hashOid->oid.len + 1] = 0;
     83    }
     84    prefix->data[6 + hashOid->oid.len + extra] = SEC_ASN1_OCTET_STRING;
     85    prefix->data[6 + hashOid->oid.len + extra + 1] = digestLen;
     86 
     87    return SECSuccess;
     88 }
     89 
     90 SECStatus
     91 _SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
     92                           const SECItem *digest,
     93                           const SECItem *dataRecoveredFromSignature,
     94                           PRBool unsafeAllowMissingParameters)
     95 {
     96    SECOidData *hashOid;
     97    pkcs1Prefix prefix;
     98    SECStatus rv;
     99 
    100    if (!digest || !digest->data ||
    101        !dataRecoveredFromSignature || !dataRecoveredFromSignature->data) {
    102        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    103        return SECFailure;
    104    }
    105 
    106    hashOid = SECOID_FindOIDByTag(digestAlg);
    107    if (hashOid == NULL) {
    108        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    109        return SECFailure;
    110    }
    111 
    112    prefix.data = NULL;
    113 
    114    rv = encodePrefix(hashOid, digest->len, &prefix, PR_TRUE);
    115 
    116    if (rv == SECSuccess) {
    117        /* We don't attempt to avoid timing attacks on these comparisons because
    118         * signature verification is a public key operation, not a private key
    119         * operation.
    120         */
    121 
    122        if (dataRecoveredFromSignature->len != prefix.len + digest->len) {
    123            PRBool lengthMismatch = PR_TRUE;
    124 #ifdef NSS_PKCS1_AllowMissingParameters
    125            if (unsafeAllowMissingParameters) {
    126                if (prefix.data) {
    127                    PORT_Free(prefix.data);
    128                    prefix.data = NULL;
    129                }
    130                rv = encodePrefix(hashOid, digest->len, &prefix, PR_FALSE);
    131                if (rv != SECSuccess ||
    132                    dataRecoveredFromSignature->len == prefix.len + digest->len) {
    133                    lengthMismatch = PR_FALSE;
    134                }
    135            }
    136 #endif
    137            if (lengthMismatch) {
    138                PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
    139                rv = SECFailure;
    140            }
    141        }
    142    }
    143 
    144    if (rv == SECSuccess) {
    145        if (memcmp(dataRecoveredFromSignature->data, prefix.data, prefix.len) ||
    146            memcmp(dataRecoveredFromSignature->data + prefix.len, digest->data,
    147                   digest->len)) {
    148            PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
    149            rv = SECFailure;
    150        }
    151    }
    152 
    153    if (prefix.data) {
    154        PORT_Free(prefix.data);
    155    }
    156 
    157    return rv;
    158 }