security/nss/lib/util/pkcs1sig.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/util/pkcs1sig.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,169 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.7 + */
     1.8 +
     1.9 +#include "pkcs1sig.h"
    1.10 +#include "hasht.h"
    1.11 +#include "secerr.h"
    1.12 +#include "secasn1t.h"
    1.13 +#include "secoid.h"
    1.14 +
    1.15 +typedef struct pkcs1PrefixStr pkcs1Prefix;
    1.16 +struct pkcs1PrefixStr {
    1.17 +    unsigned int len;
    1.18 +    PRUint8 *data;
    1.19 +};
    1.20 +
    1.21 +typedef struct pkcs1PrefixesStr pkcs1Prefixes;
    1.22 +struct pkcs1PrefixesStr {
    1.23 +    unsigned int digestLen;
    1.24 +    pkcs1Prefix prefixWithParams;
    1.25 +    pkcs1Prefix prefixWithoutParams;
    1.26 +};
    1.27 +
    1.28 +/* The value for SGN_PKCS1_DIGESTINFO_MAX_PREFIX_LEN_EXCLUDING_OID is based on
    1.29 + * the possible prefix encodings as explained below.
    1.30 + */
    1.31 +#define MAX_PREFIX_LEN_EXCLUDING_OID 10
    1.32 +
    1.33 +static SECStatus
    1.34 +encodePrefix(const SECOidData *hashOid, unsigned int digestLen,
    1.35 +             pkcs1Prefix *prefix, PRBool withParams)
    1.36 +{
    1.37 +    /* with params coding is:
    1.38 +     *  Sequence (2 bytes) {
    1.39 +     *      Sequence (2 bytes) {
    1.40 +     *               Oid (2 bytes)  {
    1.41 +     *                   Oid value (derOid->oid.len)
    1.42 +     *               }
    1.43 +     *               NULL (2 bytes)
    1.44 +     *      }
    1.45 +     *      OCTECT (2 bytes);
    1.46 +     *
    1.47 +     * without params coding is:
    1.48 +     *  Sequence (2 bytes) {
    1.49 +     *      Sequence (2 bytes) {
    1.50 +     *               Oid (2 bytes)  {
    1.51 +     *                   Oid value (derOid->oid.len)
    1.52 +     *               }
    1.53 +     *      }
    1.54 +     *      OCTECT (2 bytes);
    1.55 +     */
    1.56 +
    1.57 +    unsigned int innerSeqLen = 2 + hashOid->oid.len;
    1.58 +    unsigned int outerSeqLen = 2 + innerSeqLen + 2 + digestLen;
    1.59 +    unsigned int extra = 0;
    1.60 +
    1.61 +    if (withParams) {
    1.62 +        innerSeqLen += 2;
    1.63 +        outerSeqLen += 2;
    1.64 +        extra = 2;
    1.65 +    }
    1.66 +
    1.67 +    if (innerSeqLen >= 128 ||
    1.68 +        outerSeqLen >= 128 ||
    1.69 +        (outerSeqLen + 2 - digestLen) >
    1.70 +            (MAX_PREFIX_LEN_EXCLUDING_OID + hashOid->oid.len)) {
    1.71 +        /* this is actually a library failure, It shouldn't happen */
    1.72 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    1.73 +        return SECFailure;
    1.74 +    }
    1.75 +
    1.76 +    prefix->len = 6 + hashOid->oid.len + extra + 2;
    1.77 +    prefix->data = PORT_Alloc(prefix->len);
    1.78 +    if (!prefix->data) {
    1.79 +        PORT_SetError(SEC_ERROR_NO_MEMORY);
    1.80 +        return SECFailure;
    1.81 +    }
    1.82 +
    1.83 +    prefix->data[0] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED;
    1.84 +    prefix->data[1] = outerSeqLen;
    1.85 +    prefix->data[2] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED;
    1.86 +    prefix->data[3] = innerSeqLen;
    1.87 +    prefix->data[4] = SEC_ASN1_OBJECT_ID;
    1.88 +    prefix->data[5] = hashOid->oid.len;
    1.89 +    PORT_Memcpy(&prefix->data[6], hashOid->oid.data, hashOid->oid.len);
    1.90 +    if (withParams) {
    1.91 +        prefix->data[6 + hashOid->oid.len] = SEC_ASN1_NULL;
    1.92 +        prefix->data[6 + hashOid->oid.len + 1] = 0;
    1.93 +    }
    1.94 +    prefix->data[6 + hashOid->oid.len + extra] = SEC_ASN1_OCTET_STRING;
    1.95 +    prefix->data[6 + hashOid->oid.len + extra + 1] = digestLen;
    1.96 +
    1.97 +    return SECSuccess;
    1.98 +}
    1.99 +
   1.100 +SECStatus
   1.101 +_SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
   1.102 +                           const SECItem* digest,
   1.103 +                           const SECItem* dataRecoveredFromSignature,
   1.104 +                           PRBool unsafeAllowMissingParameters)
   1.105 +{
   1.106 +    SECOidData *hashOid;
   1.107 +    pkcs1Prefixes pp;
   1.108 +    const pkcs1Prefix* expectedPrefix;
   1.109 +    SECStatus rv, rv2, rv3;
   1.110 +
   1.111 +    if (!digest || !digest->data ||
   1.112 +        !dataRecoveredFromSignature || !dataRecoveredFromSignature->data) {
   1.113 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.114 +        return SECFailure;
   1.115 +    }
   1.116 +
   1.117 +    hashOid = SECOID_FindOIDByTag(digestAlg);
   1.118 +    if (hashOid == NULL) {
   1.119 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.120 +        return SECFailure;
   1.121 +    }
   1.122 +
   1.123 +    pp.digestLen = digest->len;
   1.124 +    pp.prefixWithParams.data = NULL;
   1.125 +    pp.prefixWithoutParams.data = NULL;
   1.126 +
   1.127 +    rv2 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithParams, PR_TRUE);
   1.128 +    rv3 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithoutParams, PR_FALSE);
   1.129 +
   1.130 +    rv = SECSuccess;
   1.131 +    if (rv2 != SECSuccess || rv3 != SECSuccess) {
   1.132 +        rv = SECFailure;
   1.133 +    }
   1.134 +
   1.135 +    if (rv == SECSuccess) {
   1.136 +        /* We don't attempt to avoid timing attacks on these comparisons because
   1.137 +         * signature verification is a public key operation, not a private key
   1.138 +         * operation.
   1.139 +         */
   1.140 +
   1.141 +        if (dataRecoveredFromSignature->len ==
   1.142 +                pp.prefixWithParams.len + pp.digestLen) {
   1.143 +            expectedPrefix = &pp.prefixWithParams;
   1.144 +        } else if (unsafeAllowMissingParameters &&
   1.145 +                   dataRecoveredFromSignature->len ==
   1.146 +                      pp.prefixWithoutParams.len + pp.digestLen) {
   1.147 +            expectedPrefix = &pp.prefixWithoutParams;
   1.148 +        } else {
   1.149 +            PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
   1.150 +            rv = SECFailure;
   1.151 +        }
   1.152 +    }
   1.153 +
   1.154 +    if (rv == SECSuccess) {
   1.155 +        if (memcmp(dataRecoveredFromSignature->data, expectedPrefix->data,
   1.156 +                   expectedPrefix->len) ||
   1.157 +            memcmp(dataRecoveredFromSignature->data + expectedPrefix->len,
   1.158 +                   digest->data, digest->len)) {
   1.159 +            PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
   1.160 +            rv = SECFailure;
   1.161 +        }
   1.162 +    }
   1.163 +
   1.164 +    if (pp.prefixWithParams.data) {
   1.165 +        PORT_Free(pp.prefixWithParams.data);
   1.166 +    }
   1.167 +    if (pp.prefixWithoutParams.data) {
   1.168 +        PORT_Free(pp.prefixWithoutParams.data);
   1.169 +    }
   1.170 +
   1.171 +    return rv;
   1.172 +}

mercurial