Coverage Report

Created: 2021-10-27 09:55

/src/nss/lib/cryptohi/secvfy.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Verification stuff.
3
 *
4
 * This Source Code Form is subject to the terms of the Mozilla Public
5
 * License, v. 2.0. If a copy of the MPL was not distributed with this
6
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8
#include <stdio.h>
9
#include "cryptohi.h"
10
#include "sechash.h"
11
#include "keyhi.h"
12
#include "secasn1.h"
13
#include "secoid.h"
14
#include "pk11func.h"
15
#include "pkcs1sig.h"
16
#include "secdig.h"
17
#include "secerr.h"
18
#include "keyi.h"
19
20
/*
21
** Recover the DigestInfo from an RSA PKCS#1 signature.
22
**
23
** If givenDigestAlg != SEC_OID_UNKNOWN, copy givenDigestAlg to digestAlgOut.
24
** Otherwise, parse the DigestInfo structure and store the decoded digest
25
** algorithm into digestAlgOut.
26
**
27
** Store the encoded DigestInfo into digestInfo.
28
** Store the DigestInfo length into digestInfoLen.
29
**
30
** This function does *not* verify that the AlgorithmIdentifier in the
31
** DigestInfo identifies givenDigestAlg or that the DigestInfo is encoded
32
** correctly; verifyPKCS1DigestInfo does that.
33
**
34
** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION
35
*/
36
static SECStatus
37
recoverPKCS1DigestInfo(SECOidTag givenDigestAlg,
38
                       /*out*/ SECOidTag *digestAlgOut,
39
                       /*out*/ unsigned char **digestInfo,
40
                       /*out*/ unsigned int *digestInfoLen,
41
                       SECKEYPublicKey *key,
42
                       const SECItem *sig, void *wincx)
43
1.09k
{
44
1.09k
    SGNDigestInfo *di = NULL;
45
1.09k
    SECItem it;
46
1.09k
    PRBool rv = SECSuccess;
47
48
1.09k
    PORT_Assert(digestAlgOut);
49
1.09k
    PORT_Assert(digestInfo);
50
1.09k
    PORT_Assert(digestInfoLen);
51
1.09k
    PORT_Assert(key);
52
1.09k
    PORT_Assert(key->keyType == rsaKey);
53
1.09k
    PORT_Assert(sig);
54
55
1.09k
    it.data = NULL;
56
1.09k
    it.len = SECKEY_PublicKeyStrength(key);
57
1.09k
    if (it.len != 0) {
58
1.09k
        it.data = (unsigned char *)PORT_Alloc(it.len);
59
1.09k
    }
60
1.09k
    if (it.len == 0 || it.data == NULL) {
61
0
        rv = SECFailure;
62
0
    }
63
64
1.09k
    if (rv == SECSuccess) {
65
        /* decrypt the block */
66
1.09k
        rv = PK11_VerifyRecover(key, sig, &it, wincx);
67
1.09k
    }
68
69
1.09k
    if (rv == SECSuccess) {
70
9
        if (givenDigestAlg != SEC_OID_UNKNOWN) {
71
            /* We don't need to parse the DigestInfo if the caller gave us the
72
             * digest algorithm to use. Later verifyPKCS1DigestInfo will verify
73
             * that the DigestInfo identifies the given digest algorithm and
74
             * that the DigestInfo is encoded absolutely correctly.
75
             */
76
9
            *digestInfoLen = it.len;
77
9
            *digestInfo = (unsigned char *)it.data;
78
9
            *digestAlgOut = givenDigestAlg;
79
9
            return SECSuccess;
80
9
        }
81
9
    }
82
83
1.08k
    if (rv == SECSuccess) {
84
        /* The caller didn't specify a digest algorithm to use, so choose the
85
         * digest algorithm by parsing the AlgorithmIdentifier within the
86
         * DigestInfo.
87
         */
88
0
        di = SGN_DecodeDigestInfo(&it);
89
0
        if (!di) {
90
0
            rv = SECFailure;
91
0
        }
92
0
    }
93
94
1.08k
    if (rv == SECSuccess) {
95
0
        *digestAlgOut = SECOID_GetAlgorithmTag(&di->digestAlgorithm);
96
0
        if (*digestAlgOut == SEC_OID_UNKNOWN) {
97
0
            rv = SECFailure;
98
0
        }
99
0
    }
100
101
1.08k
    if (di) {
102
0
        SGN_DestroyDigestInfo(di);
103
0
    }
104
105
1.08k
    if (rv == SECSuccess) {
106
0
        *digestInfoLen = it.len;
107
0
        *digestInfo = (unsigned char *)it.data;
108
1.08k
    } else {
109
1.08k
        if (it.data) {
110
1.08k
            PORT_Free(it.data);
111
1.08k
        }
112
1.08k
        *digestInfo = NULL;
113
1.08k
        *digestInfoLen = 0;
114
1.08k
        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
115
1.08k
    }
116
117
1.08k
    return rv;
118
1.09k
}
119
120
struct VFYContextStr {
121
    SECOidTag hashAlg; /* the hash algorithm */
122
    SECKEYPublicKey *key;
123
    /*
124
     * This buffer holds either the digest or the full signature
125
     * depending on the type of the signature (key->keyType).  It is
126
     * defined as a union to make sure it always has enough space.
127
     *
128
     * Use the "buffer" union member to reference the buffer.
129
     * Note: do not take the size of the "buffer" union member.  Take
130
     * the size of the union or some other union member instead.
131
     */
132
    union {
133
        unsigned char buffer[1];
134
135
        /* the full DSA signature... 40 bytes */
136
        unsigned char dsasig[DSA_MAX_SIGNATURE_LEN];
137
        /* the full ECDSA signature */
138
        unsigned char ecdsasig[2 * MAX_ECKEY_LEN];
139
        /* the full RSA signature, only used in RSA-PSS */
140
        unsigned char rsasig[(RSA_MAX_MODULUS_BITS + 7) / 8];
141
    } u;
142
    unsigned int pkcs1RSADigestInfoLen;
143
    /* the encoded DigestInfo from a RSA PKCS#1 signature */
144
    unsigned char *pkcs1RSADigestInfo;
145
    void *wincx;
146
    void *hashcx;
147
    const SECHashObject *hashobj;
148
    SECOidTag encAlg;    /* enc alg */
149
    PRBool hasSignature; /* true if the signature was provided in the
150
                          * VFY_CreateContext call.  If false, the
151
                          * signature must be provided with a
152
                          * VFY_EndWithSignature call. */
153
    SECItem *params;
154
};
155
156
static SECStatus
157
verifyPKCS1DigestInfo(const VFYContext *cx, const SECItem *digest)
158
9
{
159
9
    SECItem pkcs1DigestInfo;
160
9
    pkcs1DigestInfo.data = cx->pkcs1RSADigestInfo;
161
9
    pkcs1DigestInfo.len = cx->pkcs1RSADigestInfoLen;
162
9
    return _SGN_VerifyPKCS1DigestInfo(
163
9
        cx->hashAlg, digest, &pkcs1DigestInfo,
164
9
        PR_FALSE /*XXX: unsafeAllowMissingParameters*/);
165
9
}
166
167
/*
168
 * decode the ECDSA or DSA signature from it's DER wrapping.
169
 * The unwrapped/raw signature is placed in the buffer pointed
170
 * to by dsig and has enough room for len bytes.
171
 */
172
static SECStatus
173
decodeECorDSASignature(SECOidTag algid, const SECItem *sig, unsigned char *dsig,
174
                       unsigned int len)
175
1.52k
{
176
1.52k
    SECItem *dsasig = NULL; /* also used for ECDSA */
177
1.52k
    SECStatus rv = SECSuccess;
178
179
1.52k
    if ((algid != SEC_OID_ANSIX9_DSA_SIGNATURE) &&
180
1.52k
        (algid != SEC_OID_ANSIX962_EC_PUBLIC_KEY)) {
181
0
        if (sig->len != len) {
182
0
            PORT_SetError(SEC_ERROR_BAD_DER);
183
0
            return SECFailure;
184
0
        }
185
186
0
        PORT_Memcpy(dsig, sig->data, sig->len);
187
0
        return SECSuccess;
188
0
    }
189
190
1.52k
    if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
191
1.52k
        if (len > MAX_ECKEY_LEN * 2) {
192
0
            PORT_SetError(SEC_ERROR_BAD_DER);
193
0
            return SECFailure;
194
0
        }
195
1.52k
    }
196
1.52k
    dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len);
197
198
1.52k
    if ((dsasig == NULL) || (dsasig->len != len)) {
199
238
        rv = SECFailure;
200
1.28k
    } else {
201
1.28k
        PORT_Memcpy(dsig, dsasig->data, dsasig->len);
202
1.28k
    }
203
204
1.52k
    if (dsasig != NULL)
205
1.28k
        SECITEM_FreeItem(dsasig, PR_TRUE);
206
1.52k
    if (rv == SECFailure)
207
238
        PORT_SetError(SEC_ERROR_BAD_DER);
208
1.52k
    return rv;
209
1.52k
}
210
211
const SEC_ASN1Template hashParameterTemplate[] =
212
    {
213
      { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
214
      { SEC_ASN1_OBJECT_ID, 0 },
215
      { SEC_ASN1_SKIP_REST },
216
      { 0 }
217
    };
218
219
/*
220
 * Get just the encryption algorithm from the signature algorithm
221
 */
222
SECOidTag
223
sec_GetEncAlgFromSigAlg(SECOidTag sigAlg)
224
17.4k
{
225
    /* get the "encryption" algorithm */
226
17.4k
    switch (sigAlg) {
227
0
        case SEC_OID_PKCS1_RSA_ENCRYPTION:
228
0
        case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
229
0
        case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
230
13.3k
        case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
231
13.3k
        case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
232
13.3k
        case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
233
13.3k
        case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
234
13.5k
        case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
235
13.6k
        case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
236
13.6k
        case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
237
13.6k
            return SEC_OID_PKCS1_RSA_ENCRYPTION;
238
0
        case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
239
0
            return SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
240
241
        /* what about normal DSA? */
242
0
        case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
243
0
        case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
244
0
        case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST:
245
0
        case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST:
246
0
            return SEC_OID_ANSIX9_DSA_SIGNATURE;
247
0
        case SEC_OID_MISSI_DSS:
248
0
        case SEC_OID_MISSI_KEA_DSS:
249
0
        case SEC_OID_MISSI_KEA_DSS_OLD:
250
0
        case SEC_OID_MISSI_DSS_OLD:
251
0
            return SEC_OID_MISSI_DSS;
252
3.18k
        case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
253
3.19k
        case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
254
3.55k
        case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
255
3.63k
        case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
256
3.75k
        case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
257
3.75k
        case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
258
3.75k
        case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
259
3.75k
            return SEC_OID_ANSIX962_EC_PUBLIC_KEY;
260
        /* we don't implement MD4 hashes */
261
0
        case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
262
0
        default:
263
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
264
0
            break;
265
17.4k
    }
266
0
    return SEC_OID_UNKNOWN;
267
17.4k
}
268
269
/*
270
 * Pulls the hash algorithm, signing algorithm, and key type out of a
271
 * composite algorithm.
272
 *
273
 * sigAlg: the composite algorithm to dissect.
274
 * hashalg: address of a SECOidTag which will be set with the hash algorithm.
275
 * encalg: address of a SECOidTag which will be set with the signing alg.
276
 *
277
 * Returns: SECSuccess if the algorithm was acceptable, SECFailure if the
278
 *  algorithm was not found or was not a signing algorithm.
279
 */
280
SECStatus
281
sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg,
282
                 const SECItem *param, SECOidTag *encalgp, SECOidTag *hashalg)
283
20
{
284
20
    int len;
285
20
    PLArenaPool *arena;
286
20
    SECStatus rv;
287
20
    SECItem oid;
288
20
    SECOidTag encalg;
289
290
20
    PR_ASSERT(hashalg != NULL);
291
20
    PR_ASSERT(encalgp != NULL);
292
293
20
    switch (sigAlg) {
294
        /* We probably shouldn't be generating MD2 signatures either */
295
0
        case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
296
0
            *hashalg = SEC_OID_MD2;
297
0
            break;
298
0
        case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
299
0
            *hashalg = SEC_OID_MD5;
300
0
            break;
301
0
        case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
302
0
        case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
303
0
        case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
304
0
            *hashalg = SEC_OID_SHA1;
305
0
            break;
306
0
        case SEC_OID_PKCS1_RSA_ENCRYPTION:
307
0
            *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */
308
0
            break;
309
0
        case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
310
0
            if (param && param->data) {
311
0
                PORTCheapArenaPool tmpArena;
312
313
0
                PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
314
0
                rv = sec_DecodeRSAPSSParams(&tmpArena.arena, param,
315
0
                                            hashalg, NULL, NULL);
316
0
                PORT_DestroyCheapArena(&tmpArena);
317
318
                /* only accept hash algorithms */
319
0
                if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) {
320
                    /* error set by HASH_GetHashTypeByOidTag */
321
0
                    return SECFailure;
322
0
                }
323
0
            } else {
324
0
                *hashalg = SEC_OID_SHA1; /* default, SHA-1 */
325
0
            }
326
0
            break;
327
328
2
        case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
329
2
        case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
330
2
        case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST:
331
2
            *hashalg = SEC_OID_SHA224;
332
2
            break;
333
2
        case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
334
6
        case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
335
6
        case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST:
336
6
            *hashalg = SEC_OID_SHA256;
337
6
            break;
338
4
        case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
339
10
        case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
340
10
            *hashalg = SEC_OID_SHA384;
341
10
            break;
342
2
        case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
343
2
        case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
344
2
            *hashalg = SEC_OID_SHA512;
345
2
            break;
346
347
        /* what about normal DSA? */
348
0
        case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
349
0
        case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
350
0
        case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
351
0
            *hashalg = SEC_OID_SHA1;
352
0
            break;
353
0
        case SEC_OID_MISSI_DSS:
354
0
        case SEC_OID_MISSI_KEA_DSS:
355
0
        case SEC_OID_MISSI_KEA_DSS_OLD:
356
0
        case SEC_OID_MISSI_DSS_OLD:
357
0
            *hashalg = SEC_OID_SHA1;
358
0
            break;
359
0
        case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
360
            /* This is an EC algorithm. Recommended means the largest
361
             * hash algorithm that is not reduced by the keysize of
362
             * the EC algorithm. Note that key strength is in bytes and
363
             * algorithms are specified in bits. Never use an algorithm
364
             * weaker than sha1. */
365
0
            len = SECKEY_PublicKeyStrength(key);
366
0
            if (len < 28) { /* 28 bytes == 224 bits */
367
0
                *hashalg = SEC_OID_SHA1;
368
0
            } else if (len < 32) { /* 32 bytes == 256 bits */
369
0
                *hashalg = SEC_OID_SHA224;
370
0
            } else if (len < 48) { /* 48 bytes == 384 bits */
371
0
                *hashalg = SEC_OID_SHA256;
372
0
            } else if (len < 64) { /* 48 bytes == 512 bits */
373
0
                *hashalg = SEC_OID_SHA384;
374
0
            } else {
375
                /* use the largest in this case */
376
0
                *hashalg = SEC_OID_SHA512;
377
0
            }
378
0
            break;
379
0
        case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
380
0
            if (param == NULL) {
381
0
                PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
382
0
                return SECFailure;
383
0
            }
384
0
            arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
385
0
            if (arena == NULL) {
386
0
                return SECFailure;
387
0
            }
388
0
            rv = SEC_QuickDERDecodeItem(arena, &oid, hashParameterTemplate, param);
389
0
            if (rv == SECSuccess) {
390
0
                *hashalg = SECOID_FindOIDTag(&oid);
391
0
            }
392
0
            PORT_FreeArena(arena, PR_FALSE);
393
0
            if (rv != SECSuccess) {
394
0
                return rv;
395
0
            }
396
            /* only accept hash algorithms */
397
0
            if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) {
398
                /* error set by HASH_GetHashTypeByOidTag */
399
0
                return SECFailure;
400
0
            }
401
0
            break;
402
        /* we don't implement MD4 hashes */
403
0
        case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
404
0
        default:
405
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
406
0
            return SECFailure;
407
20
    }
408
409
20
    encalg = sec_GetEncAlgFromSigAlg(sigAlg);
410
20
    if (encalg == SEC_OID_UNKNOWN) {
411
0
        return SECFailure;
412
0
    }
413
20
    *encalgp = encalg;
414
415
20
    return SECSuccess;
416
20
}
417
418
/*
419
 * we can verify signatures that come from 2 different sources:
420
 *  one in with the signature contains a signature oid, and the other
421
 *  in which the signature is managed by a Public key (encAlg) oid
422
 *  and a hash oid. The latter is the more basic, so that's what
423
 *  our base vfyCreate function takes.
424
 *
425
 * There is one noteworthy corner case, if we are using an RSA key, and the
426
 * signature block is provided, then the hashAlg can be specified as
427
 * SEC_OID_UNKNOWN. In this case, verify will use the hash oid supplied
428
 * in the RSA signature block.
429
 */
430
static VFYContext *
431
vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig,
432
                  SECOidTag encAlg, SECOidTag hashAlg, SECOidTag *hash, void *wincx)
433
2.63k
{
434
2.63k
    VFYContext *cx;
435
2.63k
    SECStatus rv;
436
2.63k
    unsigned int sigLen;
437
2.63k
    KeyType type;
438
2.63k
    PRUint32 policyFlags;
439
440
    /* make sure the encryption algorithm matches the key type */
441
    /* RSA-PSS algorithm can be used with both rsaKey and rsaPssKey */
442
2.63k
    type = seckey_GetKeyType(encAlg);
443
2.63k
    if ((key->keyType != type) &&
444
2.63k
        ((key->keyType != rsaKey) || (type != rsaPssKey))) {
445
0
        PORT_SetError(SEC_ERROR_PKCS7_KEYALG_MISMATCH);
446
0
        return NULL;
447
0
    }
448
449
    /* check the policy on the encryption algorithm */
450
2.63k
    if ((NSS_GetAlgorithmPolicy(encAlg, &policyFlags) == SECFailure) ||
451
2.63k
        !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) {
452
0
        PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
453
0
        return NULL;
454
0
    }
455
456
2.63k
    cx = (VFYContext *)PORT_ZAlloc(sizeof(VFYContext));
457
2.63k
    if (cx == NULL) {
458
0
        goto loser;
459
0
    }
460
461
2.63k
    cx->wincx = wincx;
462
2.63k
    cx->hasSignature = (sig != NULL);
463
2.63k
    cx->encAlg = encAlg;
464
2.63k
    cx->hashAlg = hashAlg;
465
2.63k
    cx->key = SECKEY_CopyPublicKey(key);
466
2.63k
    cx->pkcs1RSADigestInfo = NULL;
467
2.63k
    rv = SECSuccess;
468
2.63k
    if (sig) {
469
2.63k
        switch (type) {
470
1.09k
            case rsaKey:
471
1.09k
                rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg,
472
1.09k
                                            &cx->pkcs1RSADigestInfo,
473
1.09k
                                            &cx->pkcs1RSADigestInfoLen,
474
1.09k
                                            cx->key,
475
1.09k
                                            sig, wincx);
476
1.09k
                break;
477
0
            case rsaPssKey:
478
0
                sigLen = SECKEY_SignatureLen(key);
479
0
                if (sigLen == 0) {
480
                    /* error set by SECKEY_SignatureLen */
481
0
                    rv = SECFailure;
482
0
                    break;
483
0
                }
484
0
                if (sig->len != sigLen) {
485
0
                    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
486
0
                    rv = SECFailure;
487
0
                    break;
488
0
                }
489
0
                PORT_Memcpy(cx->u.buffer, sig->data, sigLen);
490
0
                break;
491
0
            case dsaKey:
492
1.53k
            case ecKey:
493
1.53k
                sigLen = SECKEY_SignatureLen(key);
494
1.53k
                if (sigLen == 0) {
495
                    /* error set by SECKEY_SignatureLen */
496
12
                    rv = SECFailure;
497
12
                    break;
498
12
                }
499
1.52k
                rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen);
500
1.52k
                break;
501
0
            default:
502
0
                rv = SECFailure;
503
0
                PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
504
0
                break;
505
2.63k
        }
506
2.63k
    }
507
508
2.63k
    if (rv)
509
1.33k
        goto loser;
510
511
    /* check hash alg again, RSA may have changed it.*/
512
1.29k
    if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) {
513
        /* error set by HASH_GetHashTypeByOidTag */
514
0
        goto loser;
515
0
    }
516
    /* check the policy on the hash algorithm. Do this after
517
     * the rsa decode because some uses of this function get hash implicitly
518
     * from the RSA signature itself. */
519
1.29k
    if ((NSS_GetAlgorithmPolicy(cx->hashAlg, &policyFlags) == SECFailure) ||
520
1.29k
        !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) {
521
0
        PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
522
0
        goto loser;
523
0
    }
524
525
1.29k
    if (hash) {
526
4
        *hash = cx->hashAlg;
527
4
    }
528
1.29k
    return cx;
529
530
1.33k
loser:
531
1.33k
    if (cx) {
532
1.33k
        VFY_DestroyContext(cx, PR_TRUE);
533
1.33k
    }
534
1.33k
    return 0;
535
1.29k
}
536
537
VFYContext *
538
VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag sigAlg,
539
                  void *wincx)
540
0
{
541
0
    SECOidTag encAlg, hashAlg;
542
0
    SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL, &encAlg, &hashAlg);
543
0
    if (rv != SECSuccess) {
544
0
        return NULL;
545
0
    }
546
0
    return vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx);
547
0
}
548
549
VFYContext *
550
VFY_CreateContextDirect(const SECKEYPublicKey *key, const SECItem *sig,
551
                        SECOidTag encAlg, SECOidTag hashAlg,
552
                        SECOidTag *hash, void *wincx)
553
0
{
554
0
    return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
555
0
}
556
557
VFYContext *
558
VFY_CreateContextWithAlgorithmID(const SECKEYPublicKey *key, const SECItem *sig,
559
                                 const SECAlgorithmID *sigAlgorithm, SECOidTag *hash, void *wincx)
560
0
{
561
0
    VFYContext *cx;
562
0
    SECOidTag encAlg, hashAlg;
563
0
    SECStatus rv = sec_DecodeSigAlg(key,
564
0
                                    SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm),
565
0
                                    &sigAlgorithm->parameters, &encAlg, &hashAlg);
566
0
    if (rv != SECSuccess) {
567
0
        return NULL;
568
0
    }
569
570
0
    cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
571
0
    if (sigAlgorithm->parameters.data) {
572
0
        cx->params = SECITEM_DupItem(&sigAlgorithm->parameters);
573
0
    }
574
575
0
    return cx;
576
0
}
577
578
void
579
VFY_DestroyContext(VFYContext *cx, PRBool freeit)
580
2.63k
{
581
2.63k
    if (cx) {
582
2.63k
        if (cx->hashcx != NULL) {
583
4
            (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
584
4
            cx->hashcx = NULL;
585
4
        }
586
2.63k
        if (cx->key) {
587
2.63k
            SECKEY_DestroyPublicKey(cx->key);
588
2.63k
        }
589
2.63k
        if (cx->pkcs1RSADigestInfo) {
590
9
            PORT_Free(cx->pkcs1RSADigestInfo);
591
9
        }
592
2.63k
        if (cx->params) {
593
4
            SECITEM_FreeItem(cx->params, PR_TRUE);
594
4
        }
595
2.63k
        if (freeit) {
596
2.63k
            PORT_ZFree(cx, sizeof(VFYContext));
597
2.63k
        }
598
2.63k
    }
599
2.63k
}
600
601
SECStatus
602
VFY_Begin(VFYContext *cx)
603
4
{
604
4
    if (cx->hashcx != NULL) {
605
0
        (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
606
0
        cx->hashcx = NULL;
607
0
    }
608
609
4
    cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashAlg);
610
4
    if (!cx->hashobj)
611
0
        return SECFailure; /* error code is set */
612
613
4
    cx->hashcx = (*cx->hashobj->create)();
614
4
    if (cx->hashcx == NULL)
615
0
        return SECFailure;
616
617
4
    (*cx->hashobj->begin)(cx->hashcx);
618
4
    return SECSuccess;
619
4
}
620
621
SECStatus
622
VFY_Update(VFYContext *cx, const unsigned char *input, unsigned inputLen)
623
4
{
624
4
    if (cx->hashcx == NULL) {
625
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
626
0
        return SECFailure;
627
0
    }
628
4
    (*cx->hashobj->update)(cx->hashcx, input, inputLen);
629
4
    return SECSuccess;
630
4
}
631
632
SECStatus
633
VFY_EndWithSignature(VFYContext *cx, SECItem *sig)
634
4
{
635
4
    unsigned char final[HASH_LENGTH_MAX];
636
4
    unsigned part;
637
4
    SECItem hash, rsasig, dsasig; /* dsasig is also used for ECDSA */
638
4
    SECStatus rv;
639
640
4
    if ((cx->hasSignature == PR_FALSE) && (sig == NULL)) {
641
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
642
0
        return SECFailure;
643
0
    }
644
645
4
    if (cx->hashcx == NULL) {
646
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
647
0
        return SECFailure;
648
0
    }
649
4
    (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final));
650
4
    switch (cx->key->keyType) {
651
4
        case ecKey:
652
4
        case dsaKey:
653
4
            dsasig.data = cx->u.buffer;
654
4
            dsasig.len = SECKEY_SignatureLen(cx->key);
655
4
            if (dsasig.len == 0) {
656
0
                return SECFailure;
657
0
            }
658
4
            if (sig) {
659
0
                rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data,
660
0
                                            dsasig.len);
661
0
                if (rv != SECSuccess) {
662
0
                    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
663
0
                    return SECFailure;
664
0
                }
665
0
            }
666
4
            hash.data = final;
667
4
            hash.len = part;
668
4
            if (PK11_Verify(cx->key, &dsasig, &hash, cx->wincx) != SECSuccess) {
669
4
                PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
670
4
                return SECFailure;
671
4
            }
672
0
            break;
673
0
        case rsaKey:
674
0
            if (cx->encAlg == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
675
0
                CK_RSA_PKCS_PSS_PARAMS mech;
676
0
                SECItem mechItem = { siBuffer, (unsigned char *)&mech, sizeof(mech) };
677
0
                PORTCheapArenaPool tmpArena;
678
679
0
                PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
680
0
                rv = sec_DecodeRSAPSSParamsToMechanism(&tmpArena.arena,
681
0
                                                       cx->params,
682
0
                                                       &mech);
683
0
                PORT_DestroyCheapArena(&tmpArena);
684
0
                if (rv != SECSuccess) {
685
0
                    return SECFailure;
686
0
                }
687
688
0
                rsasig.data = cx->u.buffer;
689
0
                rsasig.len = SECKEY_SignatureLen(cx->key);
690
0
                if (rsasig.len == 0) {
691
0
                    return SECFailure;
692
0
                }
693
0
                if (sig) {
694
0
                    if (sig->len != rsasig.len) {
695
0
                        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
696
0
                        return SECFailure;
697
0
                    }
698
0
                    PORT_Memcpy(rsasig.data, sig->data, rsasig.len);
699
0
                }
700
0
                hash.data = final;
701
0
                hash.len = part;
702
0
                if (PK11_VerifyWithMechanism(cx->key, CKM_RSA_PKCS_PSS, &mechItem,
703
0
                                             &rsasig, &hash, cx->wincx) != SECSuccess) {
704
0
                    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
705
0
                    return SECFailure;
706
0
                }
707
0
            } else {
708
0
                SECItem digest;
709
0
                digest.data = final;
710
0
                digest.len = part;
711
0
                if (sig) {
712
0
                    SECOidTag hashid;
713
0
                    PORT_Assert(cx->hashAlg != SEC_OID_UNKNOWN);
714
0
                    rv = recoverPKCS1DigestInfo(cx->hashAlg, &hashid,
715
0
                                                &cx->pkcs1RSADigestInfo,
716
0
                                                &cx->pkcs1RSADigestInfoLen,
717
0
                                                cx->key,
718
0
                                                sig, cx->wincx);
719
0
                    if (rv != SECSuccess) {
720
0
                        return SECFailure;
721
0
                    }
722
0
                    PORT_Assert(cx->hashAlg == hashid);
723
0
                }
724
0
                return verifyPKCS1DigestInfo(cx, &digest);
725
0
            }
726
0
            break;
727
0
        default:
728
0
            PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
729
0
            return SECFailure; /* shouldn't happen */
730
4
    }
731
0
    return SECSuccess;
732
4
}
733
734
SECStatus
735
VFY_End(VFYContext *cx)
736
4
{
737
4
    return VFY_EndWithSignature(cx, NULL);
738
4
}
739
740
/************************************************************************/
741
/*
742
 * Verify that a previously-computed digest matches a signature.
743
 */
744
static SECStatus
745
vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key,
746
                 const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg,
747
                 void *wincx)
748
2.62k
{
749
2.62k
    SECStatus rv;
750
2.62k
    VFYContext *cx;
751
2.62k
    SECItem dsasig; /* also used for ECDSA */
752
753
2.62k
    rv = SECFailure;
754
755
2.62k
    cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx);
756
2.62k
    if (cx != NULL) {
757
1.28k
        switch (key->keyType) {
758
9
            case rsaKey:
759
9
                rv = verifyPKCS1DigestInfo(cx, digest);
760
9
                break;
761
0
            case dsaKey:
762
1.28k
            case ecKey:
763
1.28k
                dsasig.data = cx->u.buffer;
764
1.28k
                dsasig.len = SECKEY_SignatureLen(cx->key);
765
1.28k
                if (dsasig.len == 0) {
766
0
                    break;
767
0
                }
768
1.28k
                if (PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx) !=
769
1.28k
                    SECSuccess) {
770
1.28k
                    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
771
1.28k
                } else {
772
0
                    rv = SECSuccess;
773
0
                }
774
1.28k
                break;
775
0
            default:
776
0
                break;
777
1.28k
        }
778
1.28k
        VFY_DestroyContext(cx, PR_TRUE);
779
1.28k
    }
780
2.62k
    return rv;
781
2.62k
}
782
783
SECStatus
784
VFY_VerifyDigestDirect(const SECItem *digest, const SECKEYPublicKey *key,
785
                       const SECItem *sig, SECOidTag encAlg,
786
                       SECOidTag hashAlg, void *wincx)
787
2.62k
{
788
2.62k
    return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
789
2.62k
}
790
791
SECStatus
792
VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig,
793
                 SECOidTag algid, void *wincx)
794
0
{
795
0
    SECOidTag encAlg, hashAlg;
796
0
    SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg);
797
0
    if (rv != SECSuccess) {
798
0
        return SECFailure;
799
0
    }
800
0
    return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
801
0
}
802
803
/*
804
 * this function takes an optional hash oid, which the digest function
805
 * will be compared with our target hash value.
806
 */
807
SECStatus
808
VFY_VerifyDigestWithAlgorithmID(const SECItem *digest,
809
                                const SECKEYPublicKey *key, const SECItem *sig,
810
                                const SECAlgorithmID *sigAlgorithm,
811
                                SECOidTag hashCmp, void *wincx)
812
0
{
813
0
    SECOidTag encAlg, hashAlg;
814
0
    SECStatus rv = sec_DecodeSigAlg(key,
815
0
                                    SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm),
816
0
                                    &sigAlgorithm->parameters, &encAlg, &hashAlg);
817
0
    if (rv != SECSuccess) {
818
0
        return rv;
819
0
    }
820
0
    if (hashCmp != SEC_OID_UNKNOWN &&
821
0
        hashAlg != SEC_OID_UNKNOWN &&
822
0
        hashCmp != hashAlg) {
823
0
        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
824
0
        return SECFailure;
825
0
    }
826
0
    return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
827
0
}
828
829
static SECStatus
830
vfy_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key,
831
               const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg,
832
               const SECItem *params, SECOidTag *hash, void *wincx)
833
10
{
834
10
    SECStatus rv;
835
10
    VFYContext *cx;
836
837
10
    cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
838
10
    if (cx == NULL)
839
6
        return SECFailure;
840
4
    if (params) {
841
4
        cx->params = SECITEM_DupItem(params);
842
4
    }
843
844
4
    rv = VFY_Begin(cx);
845
4
    if (rv == SECSuccess) {
846
4
        rv = VFY_Update(cx, (unsigned char *)buf, len);
847
4
        if (rv == SECSuccess)
848
4
            rv = VFY_End(cx);
849
4
    }
850
851
4
    VFY_DestroyContext(cx, PR_TRUE);
852
4
    return rv;
853
10
}
854
855
SECStatus
856
VFY_VerifyDataDirect(const unsigned char *buf, int len,
857
                     const SECKEYPublicKey *key, const SECItem *sig,
858
                     SECOidTag encAlg, SECOidTag hashAlg,
859
                     SECOidTag *hash, void *wincx)
860
0
{
861
0
    return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, hash, wincx);
862
0
}
863
864
SECStatus
865
VFY_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key,
866
               const SECItem *sig, SECOidTag algid, void *wincx)
867
0
{
868
0
    SECOidTag encAlg, hashAlg;
869
0
    SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg);
870
0
    if (rv != SECSuccess) {
871
0
        return rv;
872
0
    }
873
0
    return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, NULL, wincx);
874
0
}
875
876
SECStatus
877
VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, int len,
878
                              const SECKEYPublicKey *key,
879
                              const SECItem *sig,
880
                              const SECAlgorithmID *sigAlgorithm,
881
                              SECOidTag *hash, void *wincx)
882
10
{
883
10
    SECOidTag encAlg, hashAlg;
884
10
    SECOidTag sigAlg = SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm);
885
10
    SECStatus rv = sec_DecodeSigAlg(key, sigAlg,
886
10
                                    &sigAlgorithm->parameters, &encAlg, &hashAlg);
887
10
    if (rv != SECSuccess) {
888
0
        return rv;
889
0
    }
890
10
    return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg,
891
10
                          &sigAlgorithm->parameters, hash, wincx);
892
10
}