Blame nss/lib/util/pkcs1sig.c

Packit 40b132
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit 40b132
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit 40b132
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
Packit 40b132
 */
Packit 40b132
Packit 40b132
#include "pkcs1sig.h"
Packit 40b132
#include "hasht.h"
Packit 40b132
#include "secerr.h"
Packit 40b132
#include "secasn1t.h"
Packit 40b132
#include "secoid.h"
Packit 40b132
Packit 40b132
typedef struct pkcs1PrefixStr pkcs1Prefix;
Packit 40b132
struct pkcs1PrefixStr {
Packit 40b132
    unsigned int len;
Packit 40b132
    PRUint8 *data;
Packit 40b132
};
Packit 40b132
Packit 40b132
typedef struct pkcs1PrefixesStr pkcs1Prefixes;
Packit 40b132
struct pkcs1PrefixesStr {
Packit 40b132
    unsigned int digestLen;
Packit 40b132
    pkcs1Prefix prefixWithParams;
Packit 40b132
    pkcs1Prefix prefixWithoutParams;
Packit 40b132
};
Packit 40b132
Packit 40b132
/* The value for SGN_PKCS1_DIGESTINFO_MAX_PREFIX_LEN_EXCLUDING_OID is based on
Packit 40b132
 * the possible prefix encodings as explained below.
Packit 40b132
 */
Packit 40b132
#define MAX_PREFIX_LEN_EXCLUDING_OID 10
Packit 40b132
Packit 40b132
static SECStatus
Packit 40b132
encodePrefix(const SECOidData *hashOid, unsigned int digestLen,
Packit 40b132
             pkcs1Prefix *prefix, PRBool withParams)
Packit 40b132
{
Packit 40b132
    /* with params coding is:
Packit 40b132
     *  Sequence (2 bytes) {
Packit 40b132
     *      Sequence (2 bytes) {
Packit 40b132
     *               Oid (2 bytes)  {
Packit 40b132
     *                   Oid value (derOid->oid.len)
Packit 40b132
     *               }
Packit 40b132
     *               NULL (2 bytes)
Packit 40b132
     *      }
Packit 40b132
     *      OCTECT (2 bytes);
Packit 40b132
     *
Packit 40b132
     * without params coding is:
Packit 40b132
     *  Sequence (2 bytes) {
Packit 40b132
     *      Sequence (2 bytes) {
Packit 40b132
     *               Oid (2 bytes)  {
Packit 40b132
     *                   Oid value (derOid->oid.len)
Packit 40b132
     *               }
Packit 40b132
     *      }
Packit 40b132
     *      OCTECT (2 bytes);
Packit 40b132
     */
Packit 40b132
Packit 40b132
    unsigned int innerSeqLen = 2 + hashOid->oid.len;
Packit 40b132
    unsigned int outerSeqLen = 2 + innerSeqLen + 2 + digestLen;
Packit 40b132
    unsigned int extra = 0;
Packit 40b132
Packit 40b132
    if (withParams) {
Packit 40b132
        innerSeqLen += 2;
Packit 40b132
        outerSeqLen += 2;
Packit 40b132
        extra = 2;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (innerSeqLen >= 128 ||
Packit 40b132
        outerSeqLen >= 128 ||
Packit 40b132
        (outerSeqLen + 2 - digestLen) >
Packit 40b132
            (MAX_PREFIX_LEN_EXCLUDING_OID + hashOid->oid.len)) {
Packit 40b132
        /* this is actually a library failure, It shouldn't happen */
Packit 40b132
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    prefix->len = 6 + hashOid->oid.len + extra + 2;
Packit 40b132
    prefix->data = PORT_Alloc(prefix->len);
Packit 40b132
    if (!prefix->data) {
Packit 40b132
        PORT_SetError(SEC_ERROR_NO_MEMORY);
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    prefix->data[0] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED;
Packit 40b132
    prefix->data[1] = outerSeqLen;
Packit 40b132
    prefix->data[2] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED;
Packit 40b132
    prefix->data[3] = innerSeqLen;
Packit 40b132
    prefix->data[4] = SEC_ASN1_OBJECT_ID;
Packit 40b132
    prefix->data[5] = hashOid->oid.len;
Packit 40b132
    PORT_Memcpy(&prefix->data[6], hashOid->oid.data, hashOid->oid.len);
Packit 40b132
    if (withParams) {
Packit 40b132
        prefix->data[6 + hashOid->oid.len] = SEC_ASN1_NULL;
Packit 40b132
        prefix->data[6 + hashOid->oid.len + 1] = 0;
Packit 40b132
    }
Packit 40b132
    prefix->data[6 + hashOid->oid.len + extra] = SEC_ASN1_OCTET_STRING;
Packit 40b132
    prefix->data[6 + hashOid->oid.len + extra + 1] = digestLen;
Packit 40b132
Packit 40b132
    return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
_SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
Packit 40b132
                           const SECItem* digest,
Packit 40b132
                           const SECItem* dataRecoveredFromSignature,
Packit 40b132
                           PRBool unsafeAllowMissingParameters)
Packit 40b132
{
Packit 40b132
    SECOidData *hashOid;
Packit 40b132
    pkcs1Prefixes pp;
Packit 40b132
    const pkcs1Prefix* expectedPrefix;
Packit 40b132
    SECStatus rv, rv2, rv3;
Packit 40b132
Packit 40b132
    if (!digest || !digest->data ||
Packit 40b132
        !dataRecoveredFromSignature || !dataRecoveredFromSignature->data) {
Packit 40b132
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    hashOid = SECOID_FindOIDByTag(digestAlg);
Packit 40b132
    if (hashOid == NULL) {
Packit 40b132
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    pp.digestLen = digest->len;
Packit 40b132
    pp.prefixWithParams.data = NULL;
Packit 40b132
    pp.prefixWithoutParams.data = NULL;
Packit 40b132
Packit 40b132
    rv2 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithParams, PR_TRUE);
Packit 40b132
    rv3 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithoutParams, PR_FALSE);
Packit 40b132
Packit 40b132
    rv = SECSuccess;
Packit 40b132
    if (rv2 != SECSuccess || rv3 != SECSuccess) {
Packit 40b132
        rv = SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (rv == SECSuccess) {
Packit 40b132
        /* We don't attempt to avoid timing attacks on these comparisons because
Packit 40b132
         * signature verification is a public key operation, not a private key
Packit 40b132
         * operation.
Packit 40b132
         */
Packit 40b132
Packit 40b132
        if (dataRecoveredFromSignature->len ==
Packit 40b132
                pp.prefixWithParams.len + pp.digestLen) {
Packit 40b132
            expectedPrefix = &pp.prefixWithParams;
Packit 40b132
        } else if (unsafeAllowMissingParameters &&
Packit 40b132
                   dataRecoveredFromSignature->len ==
Packit 40b132
                      pp.prefixWithoutParams.len + pp.digestLen) {
Packit 40b132
            expectedPrefix = &pp.prefixWithoutParams;
Packit 40b132
        } else {
Packit 40b132
            PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
Packit 40b132
            rv = SECFailure;
Packit 40b132
        }
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (rv == SECSuccess) {
Packit 40b132
        if (memcmp(dataRecoveredFromSignature->data, expectedPrefix->data,
Packit 40b132
                   expectedPrefix->len) ||
Packit 40b132
            memcmp(dataRecoveredFromSignature->data + expectedPrefix->len,
Packit 40b132
                   digest->data, digest->len)) {
Packit 40b132
            PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
Packit 40b132
            rv = SECFailure;
Packit 40b132
        }
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (pp.prefixWithParams.data) {
Packit 40b132
        PORT_Free(pp.prefixWithParams.data);
Packit 40b132
    }
Packit 40b132
    if (pp.prefixWithoutParams.data) {
Packit 40b132
        PORT_Free(pp.prefixWithoutParams.data);
Packit 40b132
    }
Packit 40b132
Packit 40b132
    return rv;
Packit 40b132
}