Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/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
0
{
44
0
    SGNDigestInfo *di = NULL;
45
0
    SECItem it;
46
0
    PRBool rv = SECSuccess;
47
0
48
0
    PORT_Assert(digestAlgOut);
49
0
    PORT_Assert(digestInfo);
50
0
    PORT_Assert(digestInfoLen);
51
0
    PORT_Assert(key);
52
0
    PORT_Assert(key->keyType == rsaKey);
53
0
    PORT_Assert(sig);
54
0
55
0
    it.data = NULL;
56
0
    it.len = SECKEY_PublicKeyStrength(key);
57
0
    if (it.len != 0) {
58
0
        it.data = (unsigned char *)PORT_Alloc(it.len);
59
0
    }
60
0
    if (it.len == 0 || it.data == NULL) {
61
0
        rv = SECFailure;
62
0
    }
63
0
64
0
    if (rv == SECSuccess) {
65
0
        /* decrypt the block */
66
0
        rv = PK11_VerifyRecover(key, sig, &it, wincx);
67
0
    }
68
0
69
0
    if (rv == SECSuccess) {
70
0
        if (givenDigestAlg != SEC_OID_UNKNOWN) {
71
0
            /* We don't need to parse the DigestInfo if the caller gave us the
72
0
             * digest algorithm to use. Later verifyPKCS1DigestInfo will verify
73
0
             * that the DigestInfo identifies the given digest algorithm and
74
0
             * that the DigestInfo is encoded absolutely correctly.
75
0
             */
76
0
            *digestInfoLen = it.len;
77
0
            *digestInfo = (unsigned char *)it.data;
78
0
            *digestAlgOut = givenDigestAlg;
79
0
            return SECSuccess;
80
0
        }
81
0
    }
82
0
83
0
    if (rv == SECSuccess) {
84
0
        /* The caller didn't specify a digest algorithm to use, so choose the
85
0
         * digest algorithm by parsing the AlgorithmIdentifier within the
86
0
         * DigestInfo.
87
0
         */
88
0
        di = SGN_DecodeDigestInfo(&it);
89
0
        if (!di) {
90
0
            rv = SECFailure;
91
0
        }
92
0
    }
93
0
94
0
    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
0
101
0
    if (di) {
102
0
        SGN_DestroyDigestInfo(di);
103
0
    }
104
0
105
0
    if (rv == SECSuccess) {
106
0
        *digestInfoLen = it.len;
107
0
        *digestInfo = (unsigned char *)it.data;
108
0
    } else {
109
0
        if (it.data) {
110
0
            PORT_Free(it.data);
111
0
        }
112
0
        *digestInfo = NULL;
113
0
        *digestInfoLen = 0;
114
0
        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
115
0
    }
116
0
117
0
    return rv;
118
0
}
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
0
{
159
0
    SECItem pkcs1DigestInfo;
160
0
    pkcs1DigestInfo.data = cx->pkcs1RSADigestInfo;
161
0
    pkcs1DigestInfo.len = cx->pkcs1RSADigestInfoLen;
162
0
    return _SGN_VerifyPKCS1DigestInfo(
163
0
        cx->hashAlg, digest, &pkcs1DigestInfo,
164
0
        PR_FALSE /*XXX: unsafeAllowMissingParameters*/);
165
0
}
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
0
{
176
0
    SECItem *dsasig = NULL; /* also used for ECDSA */
177
0
    SECStatus rv = SECSuccess;
178
0
179
0
    if ((algid != SEC_OID_ANSIX9_DSA_SIGNATURE) &&
180
0
        (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
0
186
0
        PORT_Memcpy(dsig, sig->data, sig->len);
187
0
        return SECSuccess;
188
0
    }
189
0
190
0
    if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
191
0
        if (len > MAX_ECKEY_LEN * 2) {
192
0
            PORT_SetError(SEC_ERROR_BAD_DER);
193
0
            return SECFailure;
194
0
        }
195
0
    }
196
0
    dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len);
197
0
198
0
    if ((dsasig == NULL) || (dsasig->len != len)) {
199
0
        rv = SECFailure;
200
0
    } else {
201
0
        PORT_Memcpy(dsig, dsasig->data, dsasig->len);
202
0
    }
203
0
204
0
    if (dsasig != NULL)
205
0
        SECITEM_FreeItem(dsasig, PR_TRUE);
206
0
    if (rv == SECFailure)
207
0
        PORT_SetError(SEC_ERROR_BAD_DER);
208
0
    return rv;
209
0
}
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
 * Pulls the hash algorithm, signing algorithm, and key type out of a
221
 * composite algorithm.
222
 *
223
 * sigAlg: the composite algorithm to dissect.
224
 * hashalg: address of a SECOidTag which will be set with the hash algorithm.
225
 * encalg: address of a SECOidTag which will be set with the signing alg.
226
 *
227
 * Returns: SECSuccess if the algorithm was acceptable, SECFailure if the
228
 *  algorithm was not found or was not a signing algorithm.
229
 */
230
SECStatus
231
sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg,
232
                 const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg)
233
0
{
234
0
    int len;
235
0
    PLArenaPool *arena;
236
0
    SECStatus rv;
237
0
    SECItem oid;
238
0
239
0
    PR_ASSERT(hashalg != NULL);
240
0
    PR_ASSERT(encalg != NULL);
241
0
242
0
    switch (sigAlg) {
243
0
        /* We probably shouldn't be generating MD2 signatures either */
244
0
        case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
245
0
            *hashalg = SEC_OID_MD2;
246
0
            break;
247
0
        case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
248
0
            *hashalg = SEC_OID_MD5;
249
0
            break;
250
0
        case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
251
0
        case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
252
0
        case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
253
0
            *hashalg = SEC_OID_SHA1;
254
0
            break;
255
0
        case SEC_OID_PKCS1_RSA_ENCRYPTION:
256
0
            *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */
257
0
            break;
258
0
        case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
259
0
            if (param && param->data) {
260
0
                SECKEYRSAPSSParams pssParam;
261
0
                arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
262
0
                if (arena == NULL) {
263
0
                    return SECFailure;
264
0
                }
265
0
                PORT_Memset(&pssParam, 0, sizeof pssParam);
266
0
                rv = SEC_QuickDERDecodeItem(arena, &pssParam,
267
0
                                            SECKEY_RSAPSSParamsTemplate,
268
0
                                            param);
269
0
                if (rv != SECSuccess) {
270
0
                    PORT_FreeArena(arena, PR_FALSE);
271
0
                    return rv;
272
0
                }
273
0
                if (pssParam.hashAlg) {
274
0
                    *hashalg = SECOID_GetAlgorithmTag(pssParam.hashAlg);
275
0
                } else {
276
0
                    *hashalg = SEC_OID_SHA1; /* default, SHA-1 */
277
0
                }
278
0
                PORT_FreeArena(arena, PR_FALSE);
279
0
                /* only accept hash algorithms */
280
0
                if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) {
281
0
                    /* error set by HASH_GetHashTypeByOidTag */
282
0
                    return SECFailure;
283
0
                }
284
0
            } else {
285
0
                *hashalg = SEC_OID_SHA1; /* default, SHA-1 */
286
0
            }
287
0
            break;
288
0
289
0
        case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
290
0
        case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
291
0
        case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST:
292
0
            *hashalg = SEC_OID_SHA224;
293
0
            break;
294
0
        case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
295
0
        case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
296
0
        case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST:
297
0
            *hashalg = SEC_OID_SHA256;
298
0
            break;
299
0
        case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
300
0
        case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
301
0
            *hashalg = SEC_OID_SHA384;
302
0
            break;
303
0
        case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
304
0
        case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
305
0
            *hashalg = SEC_OID_SHA512;
306
0
            break;
307
0
308
0
        /* what about normal DSA? */
309
0
        case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
310
0
        case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
311
0
        case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
312
0
            *hashalg = SEC_OID_SHA1;
313
0
            break;
314
0
        case SEC_OID_MISSI_DSS:
315
0
        case SEC_OID_MISSI_KEA_DSS:
316
0
        case SEC_OID_MISSI_KEA_DSS_OLD:
317
0
        case SEC_OID_MISSI_DSS_OLD:
318
0
            *hashalg = SEC_OID_SHA1;
319
0
            break;
320
0
        case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
321
0
            /* This is an EC algorithm. Recommended means the largest
322
0
             * hash algorithm that is not reduced by the keysize of
323
0
             * the EC algorithm. Note that key strength is in bytes and
324
0
             * algorithms are specified in bits. Never use an algorithm
325
0
             * weaker than sha1. */
326
0
            len = SECKEY_PublicKeyStrength(key);
327
0
            if (len < 28) { /* 28 bytes == 224 bits */
328
0
                *hashalg = SEC_OID_SHA1;
329
0
            } else if (len < 32) { /* 32 bytes == 256 bits */
330
0
                *hashalg = SEC_OID_SHA224;
331
0
            } else if (len < 48) { /* 48 bytes == 384 bits */
332
0
                *hashalg = SEC_OID_SHA256;
333
0
            } else if (len < 64) { /* 48 bytes == 512 bits */
334
0
                *hashalg = SEC_OID_SHA384;
335
0
            } else {
336
0
                /* use the largest in this case */
337
0
                *hashalg = SEC_OID_SHA512;
338
0
            }
339
0
            break;
340
0
        case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
341
0
            if (param == NULL) {
342
0
                PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
343
0
                return SECFailure;
344
0
            }
345
0
            arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
346
0
            if (arena == NULL) {
347
0
                return SECFailure;
348
0
            }
349
0
            rv = SEC_QuickDERDecodeItem(arena, &oid, hashParameterTemplate, param);
350
0
            if (rv == SECSuccess) {
351
0
                *hashalg = SECOID_FindOIDTag(&oid);
352
0
            }
353
0
            PORT_FreeArena(arena, PR_FALSE);
354
0
            if (rv != SECSuccess) {
355
0
                return rv;
356
0
            }
357
0
            /* only accept hash algorithms */
358
0
            if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) {
359
0
                /* error set by HASH_GetHashTypeByOidTag */
360
0
                return SECFailure;
361
0
            }
362
0
            break;
363
0
        /* we don't implement MD4 hashes */
364
0
        case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
365
0
        default:
366
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
367
0
            return SECFailure;
368
0
    }
369
0
    /* get the "encryption" algorithm */
370
0
    switch (sigAlg) {
371
0
        case SEC_OID_PKCS1_RSA_ENCRYPTION:
372
0
        case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
373
0
        case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
374
0
        case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
375
0
        case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
376
0
        case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
377
0
        case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
378
0
        case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
379
0
        case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
380
0
        case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
381
0
            *encalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
382
0
            break;
383
0
        case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
384
0
            *encalg = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
385
0
            break;
386
0
387
0
        /* what about normal DSA? */
388
0
        case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
389
0
        case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
390
0
        case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST:
391
0
        case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST:
392
0
            *encalg = SEC_OID_ANSIX9_DSA_SIGNATURE;
393
0
            break;
394
0
        case SEC_OID_MISSI_DSS:
395
0
        case SEC_OID_MISSI_KEA_DSS:
396
0
        case SEC_OID_MISSI_KEA_DSS_OLD:
397
0
        case SEC_OID_MISSI_DSS_OLD:
398
0
            *encalg = SEC_OID_MISSI_DSS;
399
0
            break;
400
0
        case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
401
0
        case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
402
0
        case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
403
0
        case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
404
0
        case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
405
0
        case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
406
0
        case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
407
0
            *encalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
408
0
            break;
409
0
        /* we don't implement MD4 hashes */
410
0
        case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
411
0
        default:
412
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
413
0
            return SECFailure;
414
0
    }
415
0
    return SECSuccess;
416
0
}
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
0
{
434
0
    VFYContext *cx;
435
0
    SECStatus rv;
436
0
    unsigned int sigLen;
437
0
    KeyType type;
438
0
439
0
    /* make sure the encryption algorithm matches the key type */
440
0
    /* RSA-PSS algorithm can be used with both rsaKey and rsaPssKey */
441
0
    type = seckey_GetKeyType(encAlg);
442
0
    if ((key->keyType != type) &&
443
0
        ((key->keyType != rsaKey) || (type != rsaPssKey))) {
444
0
        PORT_SetError(SEC_ERROR_PKCS7_KEYALG_MISMATCH);
445
0
        return NULL;
446
0
    }
447
0
448
0
    cx = (VFYContext *)PORT_ZAlloc(sizeof(VFYContext));
449
0
    if (cx == NULL) {
450
0
        goto loser;
451
0
    }
452
0
453
0
    cx->wincx = wincx;
454
0
    cx->hasSignature = (sig != NULL);
455
0
    cx->encAlg = encAlg;
456
0
    cx->hashAlg = hashAlg;
457
0
    cx->key = SECKEY_CopyPublicKey(key);
458
0
    cx->pkcs1RSADigestInfo = NULL;
459
0
    rv = SECSuccess;
460
0
    if (sig) {
461
0
        switch (type) {
462
0
            case rsaKey:
463
0
                rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg,
464
0
                                            &cx->pkcs1RSADigestInfo,
465
0
                                            &cx->pkcs1RSADigestInfoLen,
466
0
                                            cx->key,
467
0
                                            sig, wincx);
468
0
                break;
469
0
            case rsaPssKey:
470
0
                sigLen = SECKEY_SignatureLen(key);
471
0
                if (sigLen == 0) {
472
0
                    /* error set by SECKEY_SignatureLen */
473
0
                    rv = SECFailure;
474
0
                    break;
475
0
                }
476
0
                if (sig->len != sigLen) {
477
0
                    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
478
0
                    rv = SECFailure;
479
0
                    break;
480
0
                }
481
0
                PORT_Memcpy(cx->u.buffer, sig->data, sigLen);
482
0
                break;
483
0
            case dsaKey:
484
0
            case ecKey:
485
0
                sigLen = SECKEY_SignatureLen(key);
486
0
                if (sigLen == 0) {
487
0
                    /* error set by SECKEY_SignatureLen */
488
0
                    rv = SECFailure;
489
0
                    break;
490
0
                }
491
0
                rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen);
492
0
                break;
493
0
            default:
494
0
                rv = SECFailure;
495
0
                PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
496
0
                break;
497
0
        }
498
0
    }
499
0
500
0
    if (rv)
501
0
        goto loser;
502
0
503
0
    /* check hash alg again, RSA may have changed it.*/
504
0
    if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) {
505
0
        /* error set by HASH_GetHashTypeByOidTag */
506
0
        goto loser;
507
0
    }
508
0
509
0
    if (hash) {
510
0
        *hash = cx->hashAlg;
511
0
    }
512
0
    return cx;
513
0
514
0
loser:
515
0
    if (cx) {
516
0
        VFY_DestroyContext(cx, PR_TRUE);
517
0
    }
518
0
    return 0;
519
0
}
520
521
VFYContext *
522
VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag sigAlg,
523
                  void *wincx)
524
0
{
525
0
    SECOidTag encAlg, hashAlg;
526
0
    SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL, &encAlg, &hashAlg);
527
0
    if (rv != SECSuccess) {
528
0
        return NULL;
529
0
    }
530
0
    return vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx);
531
0
}
532
533
VFYContext *
534
VFY_CreateContextDirect(const SECKEYPublicKey *key, const SECItem *sig,
535
                        SECOidTag encAlg, SECOidTag hashAlg,
536
                        SECOidTag *hash, void *wincx)
537
0
{
538
0
    return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
539
0
}
540
541
VFYContext *
542
VFY_CreateContextWithAlgorithmID(const SECKEYPublicKey *key, const SECItem *sig,
543
                                 const SECAlgorithmID *sigAlgorithm, SECOidTag *hash, void *wincx)
544
0
{
545
0
    VFYContext *cx;
546
0
    SECOidTag encAlg, hashAlg;
547
0
    SECStatus rv = sec_DecodeSigAlg(key,
548
0
                                    SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm),
549
0
                                    &sigAlgorithm->parameters, &encAlg, &hashAlg);
550
0
    if (rv != SECSuccess) {
551
0
        return NULL;
552
0
    }
553
0
554
0
    cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
555
0
    if (sigAlgorithm->parameters.data) {
556
0
        cx->params = SECITEM_DupItem(&sigAlgorithm->parameters);
557
0
    }
558
0
559
0
    return cx;
560
0
}
561
562
void
563
VFY_DestroyContext(VFYContext *cx, PRBool freeit)
564
0
{
565
0
    if (cx) {
566
0
        if (cx->hashcx != NULL) {
567
0
            (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
568
0
            cx->hashcx = NULL;
569
0
        }
570
0
        if (cx->key) {
571
0
            SECKEY_DestroyPublicKey(cx->key);
572
0
        }
573
0
        if (cx->pkcs1RSADigestInfo) {
574
0
            PORT_Free(cx->pkcs1RSADigestInfo);
575
0
        }
576
0
        if (cx->params) {
577
0
            SECITEM_FreeItem(cx->params, PR_TRUE);
578
0
        }
579
0
        if (freeit) {
580
0
            PORT_ZFree(cx, sizeof(VFYContext));
581
0
        }
582
0
    }
583
0
}
584
585
SECStatus
586
VFY_Begin(VFYContext *cx)
587
0
{
588
0
    if (cx->hashcx != NULL) {
589
0
        (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
590
0
        cx->hashcx = NULL;
591
0
    }
592
0
593
0
    cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashAlg);
594
0
    if (!cx->hashobj)
595
0
        return SECFailure; /* error code is set */
596
0
597
0
    cx->hashcx = (*cx->hashobj->create)();
598
0
    if (cx->hashcx == NULL)
599
0
        return SECFailure;
600
0
601
0
    (*cx->hashobj->begin)(cx->hashcx);
602
0
    return SECSuccess;
603
0
}
604
605
SECStatus
606
VFY_Update(VFYContext *cx, const unsigned char *input, unsigned inputLen)
607
0
{
608
0
    if (cx->hashcx == NULL) {
609
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
610
0
        return SECFailure;
611
0
    }
612
0
    (*cx->hashobj->update)(cx->hashcx, input, inputLen);
613
0
    return SECSuccess;
614
0
}
615
616
SECStatus
617
VFY_EndWithSignature(VFYContext *cx, SECItem *sig)
618
0
{
619
0
    unsigned char final[HASH_LENGTH_MAX];
620
0
    unsigned part;
621
0
    SECItem hash, rsasig, dsasig; /* dsasig is also used for ECDSA */
622
0
    SECStatus rv;
623
0
624
0
    if ((cx->hasSignature == PR_FALSE) && (sig == NULL)) {
625
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
626
0
        return SECFailure;
627
0
    }
628
0
629
0
    if (cx->hashcx == NULL) {
630
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
631
0
        return SECFailure;
632
0
    }
633
0
    (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final));
634
0
    switch (cx->key->keyType) {
635
0
        case ecKey:
636
0
        case dsaKey:
637
0
            dsasig.data = cx->u.buffer;
638
0
            dsasig.len = SECKEY_SignatureLen(cx->key);
639
0
            if (dsasig.len == 0) {
640
0
                return SECFailure;
641
0
            }
642
0
            if (sig) {
643
0
                rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data,
644
0
                                            dsasig.len);
645
0
                if (rv != SECSuccess) {
646
0
                    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
647
0
                    return SECFailure;
648
0
                }
649
0
            }
650
0
            hash.data = final;
651
0
            hash.len = part;
652
0
            if (PK11_Verify(cx->key, &dsasig, &hash, cx->wincx) != SECSuccess) {
653
0
                PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
654
0
                return SECFailure;
655
0
            }
656
0
            break;
657
0
        case rsaKey:
658
0
            if (cx->encAlg == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
659
0
                CK_RSA_PKCS_PSS_PARAMS mech;
660
0
                SECItem mechItem = { siBuffer, (unsigned char *)&mech, sizeof(mech) };
661
0
                SECKEYRSAPSSParams params;
662
0
                PLArenaPool *arena;
663
0
664
0
                arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
665
0
                if (arena == NULL) {
666
0
                    return SECFailure;
667
0
                }
668
0
669
0
                PORT_Memset(&params, 0, sizeof(params));
670
0
                rv = SEC_QuickDERDecodeItem(arena, &params,
671
0
                                            SECKEY_RSAPSSParamsTemplate,
672
0
                                            cx->params);
673
0
                if (rv != SECSuccess) {
674
0
                    PORT_FreeArena(arena, PR_FALSE);
675
0
                    return SECFailure;
676
0
                }
677
0
                rv = sec_RSAPSSParamsToMechanism(&mech, &params);
678
0
                PORT_FreeArena(arena, PR_FALSE);
679
0
                if (rv != SECSuccess) {
680
0
                    return SECFailure;
681
0
                }
682
0
                rsasig.data = cx->u.buffer;
683
0
                rsasig.len = SECKEY_SignatureLen(cx->key);
684
0
                if (rsasig.len == 0) {
685
0
                    return SECFailure;
686
0
                }
687
0
                if (sig) {
688
0
                    if (sig->len != rsasig.len) {
689
0
                        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
690
0
                        return SECFailure;
691
0
                    }
692
0
                    PORT_Memcpy(rsasig.data, sig->data, rsasig.len);
693
0
                }
694
0
                hash.data = final;
695
0
                hash.len = part;
696
0
                if (PK11_VerifyWithMechanism(cx->key, CKM_RSA_PKCS_PSS, &mechItem,
697
0
                                             &rsasig, &hash, cx->wincx) != SECSuccess) {
698
0
                    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
699
0
                    return SECFailure;
700
0
                }
701
0
            } else {
702
0
                SECItem digest;
703
0
                digest.data = final;
704
0
                digest.len = part;
705
0
                if (sig) {
706
0
                    SECOidTag hashid;
707
0
                    PORT_Assert(cx->hashAlg != SEC_OID_UNKNOWN);
708
0
                    rv = recoverPKCS1DigestInfo(cx->hashAlg, &hashid,
709
0
                                                &cx->pkcs1RSADigestInfo,
710
0
                                                &cx->pkcs1RSADigestInfoLen,
711
0
                                                cx->key,
712
0
                                                sig, cx->wincx);
713
0
                    PORT_Assert(cx->hashAlg == hashid);
714
0
                    if (rv != SECSuccess) {
715
0
                        return SECFailure;
716
0
                    }
717
0
                }
718
0
                return verifyPKCS1DigestInfo(cx, &digest);
719
0
            }
720
0
            break;
721
0
        default:
722
0
            PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
723
0
            return SECFailure; /* shouldn't happen */
724
0
    }
725
0
    return SECSuccess;
726
0
}
727
728
SECStatus
729
VFY_End(VFYContext *cx)
730
0
{
731
0
    return VFY_EndWithSignature(cx, NULL);
732
0
}
733
734
/************************************************************************/
735
/*
736
 * Verify that a previously-computed digest matches a signature.
737
 */
738
static SECStatus
739
vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key,
740
                 const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg,
741
                 void *wincx)
742
0
{
743
0
    SECStatus rv;
744
0
    VFYContext *cx;
745
0
    SECItem dsasig; /* also used for ECDSA */
746
0
747
0
    rv = SECFailure;
748
0
749
0
    cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx);
750
0
    if (cx != NULL) {
751
0
        switch (key->keyType) {
752
0
            case rsaKey:
753
0
                rv = verifyPKCS1DigestInfo(cx, digest);
754
0
                break;
755
0
            case dsaKey:
756
0
            case ecKey:
757
0
                dsasig.data = cx->u.buffer;
758
0
                dsasig.len = SECKEY_SignatureLen(cx->key);
759
0
                if (dsasig.len == 0) {
760
0
                    break;
761
0
                }
762
0
                if (PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx) !=
763
0
                    SECSuccess) {
764
0
                    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
765
0
                } else {
766
0
                    rv = SECSuccess;
767
0
                }
768
0
                break;
769
0
            default:
770
0
                break;
771
0
        }
772
0
        VFY_DestroyContext(cx, PR_TRUE);
773
0
    }
774
0
    return rv;
775
0
}
776
777
SECStatus
778
VFY_VerifyDigestDirect(const SECItem *digest, const SECKEYPublicKey *key,
779
                       const SECItem *sig, SECOidTag encAlg,
780
                       SECOidTag hashAlg, void *wincx)
781
0
{
782
0
    return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
783
0
}
784
785
SECStatus
786
VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig,
787
                 SECOidTag algid, void *wincx)
788
0
{
789
0
    SECOidTag encAlg, hashAlg;
790
0
    SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg);
791
0
    if (rv != SECSuccess) {
792
0
        return SECFailure;
793
0
    }
794
0
    return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
795
0
}
796
797
/*
798
 * this function takes an optional hash oid, which the digest function
799
 * will be compared with our target hash value.
800
 */
801
SECStatus
802
VFY_VerifyDigestWithAlgorithmID(const SECItem *digest,
803
                                const SECKEYPublicKey *key, const SECItem *sig,
804
                                const SECAlgorithmID *sigAlgorithm,
805
                                SECOidTag hashCmp, void *wincx)
806
0
{
807
0
    SECOidTag encAlg, hashAlg;
808
0
    SECStatus rv = sec_DecodeSigAlg(key,
809
0
                                    SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm),
810
0
                                    &sigAlgorithm->parameters, &encAlg, &hashAlg);
811
0
    if (rv != SECSuccess) {
812
0
        return rv;
813
0
    }
814
0
    if (hashCmp != SEC_OID_UNKNOWN &&
815
0
        hashAlg != SEC_OID_UNKNOWN &&
816
0
        hashCmp != hashAlg) {
817
0
        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
818
0
        return SECFailure;
819
0
    }
820
0
    return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
821
0
}
822
823
static SECStatus
824
vfy_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key,
825
               const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg,
826
               const SECItem *params, SECOidTag *hash, void *wincx)
827
0
{
828
0
    SECStatus rv;
829
0
    VFYContext *cx;
830
0
831
0
    cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
832
0
    if (cx == NULL)
833
0
        return SECFailure;
834
0
    if (params) {
835
0
        cx->params = SECITEM_DupItem(params);
836
0
    }
837
0
838
0
    rv = VFY_Begin(cx);
839
0
    if (rv == SECSuccess) {
840
0
        rv = VFY_Update(cx, (unsigned char *)buf, len);
841
0
        if (rv == SECSuccess)
842
0
            rv = VFY_End(cx);
843
0
    }
844
0
845
0
    VFY_DestroyContext(cx, PR_TRUE);
846
0
    return rv;
847
0
}
848
849
SECStatus
850
VFY_VerifyDataDirect(const unsigned char *buf, int len,
851
                     const SECKEYPublicKey *key, const SECItem *sig,
852
                     SECOidTag encAlg, SECOidTag hashAlg,
853
                     SECOidTag *hash, void *wincx)
854
0
{
855
0
    return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, hash, wincx);
856
0
}
857
858
SECStatus
859
VFY_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key,
860
               const SECItem *sig, SECOidTag algid, void *wincx)
861
0
{
862
0
    SECOidTag encAlg, hashAlg;
863
0
    SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg);
864
0
    if (rv != SECSuccess) {
865
0
        return rv;
866
0
    }
867
0
    return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, NULL, wincx);
868
0
}
869
870
SECStatus
871
VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, int len,
872
                              const SECKEYPublicKey *key,
873
                              const SECItem *sig,
874
                              const SECAlgorithmID *sigAlgorithm,
875
                              SECOidTag *hash, void *wincx)
876
0
{
877
0
    SECOidTag encAlg, hashAlg;
878
0
    SECOidTag sigAlg = SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm);
879
0
    SECStatus rv = sec_DecodeSigAlg(key, sigAlg,
880
0
                                    &sigAlgorithm->parameters, &encAlg, &hashAlg);
881
0
    if (rv != SECSuccess) {
882
0
        return rv;
883
0
    }
884
0
    return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg,
885
0
                          &sigAlgorithm->parameters, hash, wincx);
886
0
}