Coverage Report

Created: 2024-11-21 07:03

/src/nss-nspr/nss/lib/util/pkcs1sig.c
Line
Count
Source (jump to first uncovered line)
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
6
#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
6
{
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
6
    unsigned int innerSeqLen = 2 + hashOid->oid.len;
48
6
    unsigned int outerSeqLen = 2 + innerSeqLen + 2 + digestLen;
49
6
    unsigned int extra = 0;
50
51
6
    if (withParams) {
52
6
        innerSeqLen += 2;
53
6
        outerSeqLen += 2;
54
6
        extra = 2;
55
6
    }
56
57
6
    if (innerSeqLen >= 128 ||
58
6
        outerSeqLen >= 128 ||
59
6
        (outerSeqLen + 2 - digestLen) >
60
6
            (MAX_PREFIX_LEN_EXCLUDING_OID + hashOid->oid.len)) {
61
        /* this is actually a library failure, It shouldn't happen */
62
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
63
0
        return SECFailure;
64
0
    }
65
66
6
    prefix->len = 6 + hashOid->oid.len + extra + 2;
67
6
    prefix->data = PORT_Alloc(prefix->len);
68
6
    if (!prefix->data) {
69
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
70
0
        return SECFailure;
71
0
    }
72
73
6
    prefix->data[0] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED;
74
6
    prefix->data[1] = outerSeqLen;
75
6
    prefix->data[2] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED;
76
6
    prefix->data[3] = innerSeqLen;
77
6
    prefix->data[4] = SEC_ASN1_OBJECT_ID;
78
6
    prefix->data[5] = hashOid->oid.len;
79
6
    PORT_Memcpy(&prefix->data[6], hashOid->oid.data, hashOid->oid.len);
80
6
    if (withParams) {
81
6
        prefix->data[6 + hashOid->oid.len] = SEC_ASN1_NULL;
82
6
        prefix->data[6 + hashOid->oid.len + 1] = 0;
83
6
    }
84
6
    prefix->data[6 + hashOid->oid.len + extra] = SEC_ASN1_OCTET_STRING;
85
6
    prefix->data[6 + hashOid->oid.len + extra + 1] = digestLen;
86
87
6
    return SECSuccess;
88
6
}
89
90
SECStatus
91
_SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
92
                           const SECItem *digest,
93
                           const SECItem *dataRecoveredFromSignature,
94
                           PRBool unsafeAllowMissingParameters)
95
6
{
96
6
    SECOidData *hashOid;
97
6
    pkcs1Prefix prefix;
98
6
    SECStatus rv;
99
100
6
    if (!digest || !digest->data ||
101
6
        !dataRecoveredFromSignature || !dataRecoveredFromSignature->data) {
102
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
103
0
        return SECFailure;
104
0
    }
105
106
6
    hashOid = SECOID_FindOIDByTag(digestAlg);
107
6
    if (hashOid == NULL) {
108
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
109
0
        return SECFailure;
110
0
    }
111
112
6
    prefix.data = NULL;
113
114
6
    rv = encodePrefix(hashOid, digest->len, &prefix, PR_TRUE);
115
116
6
    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
6
        if (dataRecoveredFromSignature->len != prefix.len + digest->len) {
123
0
            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
0
            if (lengthMismatch) {
138
0
                PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
139
0
                rv = SECFailure;
140
0
            }
141
0
        }
142
6
    }
143
144
6
    if (rv == SECSuccess) {
145
6
        if (memcmp(dataRecoveredFromSignature->data, prefix.data, prefix.len) ||
146
6
            memcmp(dataRecoveredFromSignature->data + prefix.len, digest->data,
147
6
                   digest->len)) {
148
0
            PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
149
0
            rv = SECFailure;
150
0
        }
151
6
    }
152
153
6
    if (prefix.data) {
154
6
        PORT_Free(prefix.data);
155
6
    }
156
157
6
    return rv;
158
6
}