Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/nss/lib/cryptohi/secsign.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Signature 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 "secder.h"
12
#include "keyhi.h"
13
#include "secoid.h"
14
#include "secdig.h"
15
#include "pk11func.h"
16
#include "secerr.h"
17
#include "keyi.h"
18
19
struct SGNContextStr {
20
    SECOidTag signalg;
21
    SECOidTag hashalg;
22
    void *hashcx;
23
    const SECHashObject *hashobj;
24
    SECKEYPrivateKey *key;
25
    SECItem *params;
26
};
27
28
static SGNContext *
29
sgn_NewContext(SECOidTag alg, SECItem *params, SECKEYPrivateKey *key)
30
0
{
31
0
    SGNContext *cx;
32
0
    SECOidTag hashalg, signalg;
33
0
    KeyType keyType;
34
0
    SECStatus rv;
35
0
36
0
    /* OK, map a PKCS #7 hash and encrypt algorithm into
37
0
     * a standard hashing algorithm. Why did we pass in the whole
38
0
     * PKCS #7 algTag if we were just going to change here you might
39
0
     * ask. Well the answer is for some cards we may have to do the
40
0
     * hashing on card. It may not support CKM_RSA_PKCS sign algorithm,
41
0
     * it may just support CKM_SHA1_RSA_PKCS and/or CKM_MD5_RSA_PKCS.
42
0
     */
43
0
    /* we have a private key, not a public key, so don't pass it in */
44
0
    rv = sec_DecodeSigAlg(NULL, alg, params, &signalg, &hashalg);
45
0
    if (rv != SECSuccess) {
46
0
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
47
0
        return 0;
48
0
    }
49
0
    keyType = seckey_GetKeyType(signalg);
50
0
51
0
    /* verify our key type */
52
0
    if (key->keyType != keyType &&
53
0
        !((key->keyType == dsaKey) && (keyType == fortezzaKey)) &&
54
0
        !((key->keyType == rsaKey) && (keyType == rsaPssKey))) {
55
0
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
56
0
        return 0;
57
0
    }
58
0
59
0
    cx = (SGNContext *)PORT_ZAlloc(sizeof(SGNContext));
60
0
    if (cx) {
61
0
        cx->hashalg = hashalg;
62
0
        cx->signalg = signalg;
63
0
        cx->key = key;
64
0
        cx->params = params;
65
0
    }
66
0
    return cx;
67
0
}
68
69
SGNContext *
70
SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key)
71
0
{
72
0
    return sgn_NewContext(alg, NULL, key);
73
0
}
74
75
SGNContext *
76
SGN_NewContextWithAlgorithmID(SECAlgorithmID *alg, SECKEYPrivateKey *key)
77
0
{
78
0
    SECOidTag tag = SECOID_GetAlgorithmTag(alg);
79
0
    return sgn_NewContext(tag, &alg->parameters, key);
80
0
}
81
82
void
83
SGN_DestroyContext(SGNContext *cx, PRBool freeit)
84
0
{
85
0
    if (cx) {
86
0
        if (cx->hashcx != NULL) {
87
0
            (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
88
0
            cx->hashcx = NULL;
89
0
        }
90
0
        if (freeit) {
91
0
            PORT_ZFree(cx, sizeof(SGNContext));
92
0
        }
93
0
    }
94
0
}
95
96
SECStatus
97
SGN_Begin(SGNContext *cx)
98
0
{
99
0
    if (cx->hashcx != NULL) {
100
0
        (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
101
0
        cx->hashcx = NULL;
102
0
    }
103
0
104
0
    cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashalg);
105
0
    if (!cx->hashobj)
106
0
        return SECFailure; /* error code is already set */
107
0
108
0
    cx->hashcx = (*cx->hashobj->create)();
109
0
    if (cx->hashcx == NULL)
110
0
        return SECFailure;
111
0
112
0
    (*cx->hashobj->begin)(cx->hashcx);
113
0
    return SECSuccess;
114
0
}
115
116
SECStatus
117
SGN_Update(SGNContext *cx, const unsigned char *input, unsigned int inputLen)
118
0
{
119
0
    if (cx->hashcx == NULL) {
120
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
121
0
        return SECFailure;
122
0
    }
123
0
    (*cx->hashobj->update)(cx->hashcx, input, inputLen);
124
0
    return SECSuccess;
125
0
}
126
127
/* XXX Old template; want to expunge it eventually. */
128
static DERTemplate SECAlgorithmIDTemplate[] = {
129
    { DER_SEQUENCE,
130
      0, NULL, sizeof(SECAlgorithmID) },
131
    { DER_OBJECT_ID,
132
      offsetof(SECAlgorithmID, algorithm) },
133
    { DER_OPTIONAL | DER_ANY,
134
      offsetof(SECAlgorithmID, parameters) },
135
    { 0 }
136
};
137
138
/*
139
 * XXX OLD Template.  Once all uses have been switched over to new one,
140
 * remove this.
141
 */
142
static DERTemplate SGNDigestInfoTemplate[] = {
143
    { DER_SEQUENCE,
144
      0, NULL, sizeof(SGNDigestInfo) },
145
    { DER_INLINE,
146
      offsetof(SGNDigestInfo, digestAlgorithm),
147
      SECAlgorithmIDTemplate },
148
    { DER_OCTET_STRING,
149
      offsetof(SGNDigestInfo, digest) },
150
    { 0 }
151
};
152
153
SECStatus
154
SGN_End(SGNContext *cx, SECItem *result)
155
0
{
156
0
    unsigned char digest[HASH_LENGTH_MAX];
157
0
    unsigned part1;
158
0
    int signatureLen;
159
0
    SECStatus rv;
160
0
    SECItem digder, sigitem;
161
0
    PLArenaPool *arena = 0;
162
0
    SECKEYPrivateKey *privKey = cx->key;
163
0
    SGNDigestInfo *di = 0;
164
0
165
0
    result->data = 0;
166
0
    digder.data = 0;
167
0
    sigitem.data = 0;
168
0
169
0
    /* Finish up digest function */
170
0
    if (cx->hashcx == NULL) {
171
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
172
0
        return SECFailure;
173
0
    }
174
0
    (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest));
175
0
176
0
    if (privKey->keyType == rsaKey &&
177
0
        cx->signalg != SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
178
0
179
0
        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
180
0
        if (!arena) {
181
0
            rv = SECFailure;
182
0
            goto loser;
183
0
        }
184
0
185
0
        /* Construct digest info */
186
0
        di = SGN_CreateDigestInfo(cx->hashalg, digest, part1);
187
0
        if (!di) {
188
0
            rv = SECFailure;
189
0
            goto loser;
190
0
        }
191
0
192
0
        /* Der encode the digest as a DigestInfo */
193
0
        rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate,
194
0
                        di);
195
0
        if (rv != SECSuccess) {
196
0
            goto loser;
197
0
        }
198
0
    } else {
199
0
        digder.data = digest;
200
0
        digder.len = part1;
201
0
    }
202
0
203
0
    /*
204
0
    ** Encrypt signature after constructing appropriate PKCS#1 signature
205
0
    ** block
206
0
    */
207
0
    signatureLen = PK11_SignatureLen(privKey);
208
0
    if (signatureLen <= 0) {
209
0
        PORT_SetError(SEC_ERROR_INVALID_KEY);
210
0
        rv = SECFailure;
211
0
        goto loser;
212
0
    }
213
0
    sigitem.len = signatureLen;
214
0
    sigitem.data = (unsigned char *)PORT_Alloc(signatureLen);
215
0
216
0
    if (sigitem.data == NULL) {
217
0
        rv = SECFailure;
218
0
        goto loser;
219
0
    }
220
0
221
0
    if (cx->signalg == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
222
0
        CK_RSA_PKCS_PSS_PARAMS mech;
223
0
        SECItem mechItem = { siBuffer, (unsigned char *)&mech, sizeof(mech) };
224
0
225
0
        PORT_Memset(&mech, 0, sizeof(mech));
226
0
227
0
        if (cx->params && cx->params->data) {
228
0
            SECKEYRSAPSSParams params;
229
0
230
0
            arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
231
0
            if (!arena) {
232
0
                rv = SECFailure;
233
0
                goto loser;
234
0
            }
235
0
236
0
            PORT_Memset(&params, 0, sizeof(params));
237
0
            rv = SEC_QuickDERDecodeItem(arena, &params,
238
0
                                        SECKEY_RSAPSSParamsTemplate,
239
0
                                        cx->params);
240
0
            if (rv != SECSuccess) {
241
0
                goto loser;
242
0
            }
243
0
            rv = sec_RSAPSSParamsToMechanism(&mech, &params);
244
0
            if (rv != SECSuccess) {
245
0
                goto loser;
246
0
            }
247
0
        } else {
248
0
            mech.hashAlg = CKM_SHA_1;
249
0
            mech.mgf = CKG_MGF1_SHA1;
250
0
            mech.sLen = digder.len;
251
0
        }
252
0
        rv = PK11_SignWithMechanism(privKey, CKM_RSA_PKCS_PSS, &mechItem,
253
0
                                    &sigitem, &digder);
254
0
        if (rv != SECSuccess) {
255
0
            goto loser;
256
0
        }
257
0
    } else {
258
0
        rv = PK11_Sign(privKey, &sigitem, &digder);
259
0
        if (rv != SECSuccess) {
260
0
            goto loser;
261
0
        }
262
0
    }
263
0
264
0
    if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) ||
265
0
        (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) {
266
0
        /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */
267
0
        rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len);
268
0
        if (rv != SECSuccess)
269
0
            goto loser;
270
0
        SECITEM_FreeItem(&sigitem, PR_FALSE);
271
0
    } else {
272
0
        result->len = sigitem.len;
273
0
        result->data = sigitem.data;
274
0
    }
275
0
276
0
loser:
277
0
    if (rv != SECSuccess) {
278
0
        SECITEM_FreeItem(&sigitem, PR_FALSE);
279
0
    }
280
0
    SGN_DestroyDigestInfo(di);
281
0
    if (arena != NULL) {
282
0
        PORT_FreeArena(arena, PR_FALSE);
283
0
    }
284
0
    return rv;
285
0
}
286
287
/************************************************************************/
288
289
static SECStatus
290
sec_SignData(SECItem *res, const unsigned char *buf, int len,
291
             SECKEYPrivateKey *pk, SECOidTag algid, SECItem *params)
292
0
{
293
0
    SECStatus rv;
294
0
    SGNContext *sgn;
295
0
296
0
    sgn = sgn_NewContext(algid, params, pk);
297
0
298
0
    if (sgn == NULL)
299
0
        return SECFailure;
300
0
301
0
    rv = SGN_Begin(sgn);
302
0
    if (rv != SECSuccess)
303
0
        goto loser;
304
0
305
0
    rv = SGN_Update(sgn, buf, len);
306
0
    if (rv != SECSuccess)
307
0
        goto loser;
308
0
309
0
    rv = SGN_End(sgn, res);
310
0
311
0
loser:
312
0
    SGN_DestroyContext(sgn, PR_TRUE);
313
0
    return rv;
314
0
}
315
316
/*
317
** Sign a block of data returning in result a bunch of bytes that are the
318
** signature. Returns zero on success, an error code on failure.
319
*/
320
SECStatus
321
SEC_SignData(SECItem *res, const unsigned char *buf, int len,
322
             SECKEYPrivateKey *pk, SECOidTag algid)
323
0
{
324
0
    return sec_SignData(res, buf, len, pk, algid, NULL);
325
0
}
326
327
SECStatus
328
SEC_SignDataWithAlgorithmID(SECItem *res, const unsigned char *buf, int len,
329
                            SECKEYPrivateKey *pk, SECAlgorithmID *algid)
330
0
{
331
0
    SECOidTag tag = SECOID_GetAlgorithmTag(algid);
332
0
    return sec_SignData(res, buf, len, pk, tag, &algid->parameters);
333
0
}
334
335
/************************************************************************/
336
337
DERTemplate CERTSignedDataTemplate[] =
338
    {
339
      { DER_SEQUENCE,
340
        0, NULL, sizeof(CERTSignedData) },
341
      { DER_ANY,
342
        offsetof(CERTSignedData, data) },
343
      { DER_INLINE,
344
        offsetof(CERTSignedData, signatureAlgorithm),
345
        SECAlgorithmIDTemplate },
346
      { DER_BIT_STRING,
347
        offsetof(CERTSignedData, signature) },
348
      { 0 }
349
    };
350
351
SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
352
353
const SEC_ASN1Template CERT_SignedDataTemplate[] =
354
    {
355
      { SEC_ASN1_SEQUENCE,
356
        0, NULL, sizeof(CERTSignedData) },
357
      { SEC_ASN1_ANY,
358
        offsetof(CERTSignedData, data) },
359
      { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
360
        offsetof(CERTSignedData, signatureAlgorithm),
361
        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
362
      { SEC_ASN1_BIT_STRING,
363
        offsetof(CERTSignedData, signature) },
364
      { 0 }
365
    };
366
367
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedDataTemplate)
368
369
static SECStatus
370
sec_DerSignData(PLArenaPool *arena, SECItem *result,
371
                const unsigned char *buf, int len, SECKEYPrivateKey *pk,
372
                SECOidTag algID, SECItem *params)
373
0
{
374
0
    SECItem it;
375
0
    CERTSignedData sd;
376
0
    SECStatus rv;
377
0
378
0
    it.data = 0;
379
0
380
0
    /* XXX We should probably have some asserts here to make sure the key type
381
0
     * and algID match
382
0
     */
383
0
384
0
    if (algID == SEC_OID_UNKNOWN) {
385
0
        switch (pk->keyType) {
386
0
            case rsaKey:
387
0
                algID = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
388
0
                break;
389
0
            case dsaKey:
390
0
                /* get Signature length (= q_len*2) and work from there */
391
0
                switch (PK11_SignatureLen(pk)) {
392
0
                    case 320:
393
0
                        algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
394
0
                        break;
395
0
                    case 448:
396
0
                        algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST;
397
0
                        break;
398
0
                    case 512:
399
0
                    default:
400
0
                        algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST;
401
0
                        break;
402
0
                }
403
0
                break;
404
0
            case ecKey:
405
0
                algID = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE;
406
0
                break;
407
0
            default:
408
0
                PORT_SetError(SEC_ERROR_INVALID_KEY);
409
0
                return SECFailure;
410
0
        }
411
0
    }
412
0
413
0
    /* Sign input buffer */
414
0
    rv = sec_SignData(&it, buf, len, pk, algID, params);
415
0
    if (rv)
416
0
        goto loser;
417
0
418
0
    /* Fill out SignedData object */
419
0
    PORT_Memset(&sd, 0, sizeof(sd));
420
0
    sd.data.data = (unsigned char *)buf;
421
0
    sd.data.len = len;
422
0
    sd.signature.data = it.data;
423
0
    sd.signature.len = it.len << 3; /* convert to bit string */
424
0
    rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, params);
425
0
    if (rv)
426
0
        goto loser;
427
0
428
0
    /* DER encode the signed data object */
429
0
    rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd);
430
0
/* FALL THROUGH */
431
0
432
0
loser:
433
0
    PORT_Free(it.data);
434
0
    return rv;
435
0
}
436
437
SECStatus
438
SEC_DerSignData(PLArenaPool *arena, SECItem *result,
439
                const unsigned char *buf, int len, SECKEYPrivateKey *pk,
440
                SECOidTag algID)
441
0
{
442
0
    return sec_DerSignData(arena, result, buf, len, pk, algID, NULL);
443
0
}
444
445
SECStatus
446
SEC_DerSignDataWithAlgorithmID(PLArenaPool *arena, SECItem *result,
447
                               const unsigned char *buf, int len,
448
                               SECKEYPrivateKey *pk,
449
                               SECAlgorithmID *algID)
450
0
{
451
0
    SECOidTag tag = SECOID_GetAlgorithmTag(algID);
452
0
    return sec_DerSignData(arena, result, buf, len, pk, tag, &algID->parameters);
453
0
}
454
455
SECStatus
456
SGN_Digest(SECKEYPrivateKey *privKey,
457
           SECOidTag algtag, SECItem *result, SECItem *digest)
458
0
{
459
0
    int modulusLen;
460
0
    SECStatus rv;
461
0
    SECItem digder;
462
0
    PLArenaPool *arena = 0;
463
0
    SGNDigestInfo *di = 0;
464
0
465
0
    result->data = 0;
466
0
467
0
    if (privKey->keyType == rsaKey) {
468
0
469
0
        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
470
0
        if (!arena) {
471
0
            rv = SECFailure;
472
0
            goto loser;
473
0
        }
474
0
475
0
        /* Construct digest info */
476
0
        di = SGN_CreateDigestInfo(algtag, digest->data, digest->len);
477
0
        if (!di) {
478
0
            rv = SECFailure;
479
0
            goto loser;
480
0
        }
481
0
482
0
        /* Der encode the digest as a DigestInfo */
483
0
        rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate,
484
0
                        di);
485
0
        if (rv != SECSuccess) {
486
0
            goto loser;
487
0
        }
488
0
    } else {
489
0
        digder.data = digest->data;
490
0
        digder.len = digest->len;
491
0
    }
492
0
493
0
    /*
494
0
    ** Encrypt signature after constructing appropriate PKCS#1 signature
495
0
    ** block
496
0
    */
497
0
    modulusLen = PK11_SignatureLen(privKey);
498
0
    if (modulusLen <= 0) {
499
0
        PORT_SetError(SEC_ERROR_INVALID_KEY);
500
0
        rv = SECFailure;
501
0
        goto loser;
502
0
    }
503
0
    result->len = modulusLen;
504
0
    result->data = (unsigned char *)PORT_Alloc(modulusLen);
505
0
    result->type = siBuffer;
506
0
507
0
    if (result->data == NULL) {
508
0
        rv = SECFailure;
509
0
        goto loser;
510
0
    }
511
0
512
0
    rv = PK11_Sign(privKey, result, &digder);
513
0
    if (rv != SECSuccess) {
514
0
        PORT_Free(result->data);
515
0
        result->data = NULL;
516
0
    }
517
0
518
0
loser:
519
0
    SGN_DestroyDigestInfo(di);
520
0
    if (arena != NULL) {
521
0
        PORT_FreeArena(arena, PR_FALSE);
522
0
    }
523
0
    return rv;
524
0
}
525
526
SECOidTag
527
SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag)
528
0
{
529
0
    SECOidTag sigTag = SEC_OID_UNKNOWN;
530
0
531
0
    switch (keyType) {
532
0
        case rsaKey:
533
0
            switch (hashAlgTag) {
534
0
                case SEC_OID_MD2:
535
0
                    sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
536
0
                    break;
537
0
                case SEC_OID_MD5:
538
0
                    sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
539
0
                    break;
540
0
                case SEC_OID_SHA1:
541
0
                    sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
542
0
                    break;
543
0
                case SEC_OID_SHA224:
544
0
                    sigTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION;
545
0
                    break;
546
0
                case SEC_OID_UNKNOWN: /* default for RSA if not specified */
547
0
                case SEC_OID_SHA256:
548
0
                    sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
549
0
                    break;
550
0
                case SEC_OID_SHA384:
551
0
                    sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
552
0
                    break;
553
0
                case SEC_OID_SHA512:
554
0
                    sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
555
0
                    break;
556
0
                default:
557
0
                    break;
558
0
            }
559
0
            break;
560
0
        case dsaKey:
561
0
            switch (hashAlgTag) {
562
0
                case SEC_OID_SHA1:
563
0
                    sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
564
0
                    break;
565
0
                case SEC_OID_SHA224:
566
0
                    sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST;
567
0
                    break;
568
0
                case SEC_OID_UNKNOWN: /* default for DSA if not specified */
569
0
                case SEC_OID_SHA256:
570
0
                    sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST;
571
0
                    break;
572
0
                default:
573
0
                    break;
574
0
            }
575
0
            break;
576
0
        case ecKey:
577
0
            switch (hashAlgTag) {
578
0
                case SEC_OID_SHA1:
579
0
                    sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE;
580
0
                    break;
581
0
                case SEC_OID_SHA224:
582
0
                    sigTag = SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE;
583
0
                    break;
584
0
                case SEC_OID_UNKNOWN: /* default for ECDSA if not specified */
585
0
                case SEC_OID_SHA256:
586
0
                    sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE;
587
0
                    break;
588
0
                case SEC_OID_SHA384:
589
0
                    sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE;
590
0
                    break;
591
0
                case SEC_OID_SHA512:
592
0
                    sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE;
593
0
                    break;
594
0
                default:
595
0
                    break;
596
0
            }
597
0
        default:
598
0
            break;
599
0
    }
600
0
    return sigTag;
601
0
}
602
603
static SECItem *
604
sec_CreateRSAPSSParameters(PLArenaPool *arena,
605
                           SECItem *result,
606
                           SECOidTag hashAlgTag,
607
                           const SECItem *params,
608
                           const SECKEYPrivateKey *key)
609
0
{
610
0
    SECKEYRSAPSSParams pssParams;
611
0
    int modBytes, hashLength;
612
0
    unsigned long saltLength;
613
0
    PRBool defaultSHA1 = PR_FALSE;
614
0
    SECStatus rv;
615
0
616
0
    if (key->keyType != rsaKey && key->keyType != rsaPssKey) {
617
0
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
618
0
        return NULL;
619
0
    }
620
0
621
0
    PORT_Memset(&pssParams, 0, sizeof(pssParams));
622
0
623
0
    if (params && params->data) {
624
0
        /* The parameters field should either be empty or contain
625
0
         * valid RSA-PSS parameters */
626
0
        PORT_Assert(!(params->len == 2 &&
627
0
                      params->data[0] == SEC_ASN1_NULL &&
628
0
                      params->data[1] == 0));
629
0
        rv = SEC_QuickDERDecodeItem(arena, &pssParams,
630
0
                                    SECKEY_RSAPSSParamsTemplate,
631
0
                                    params);
632
0
        if (rv != SECSuccess) {
633
0
            return NULL;
634
0
        }
635
0
        defaultSHA1 = PR_TRUE;
636
0
    }
637
0
638
0
    if (pssParams.trailerField.data) {
639
0
        unsigned long trailerField;
640
0
641
0
        rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.trailerField,
642
0
                                   &trailerField);
643
0
        if (rv != SECSuccess) {
644
0
            return NULL;
645
0
        }
646
0
        if (trailerField != 1) {
647
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
648
0
            return NULL;
649
0
        }
650
0
    }
651
0
652
0
    modBytes = PK11_GetPrivateModulusLen((SECKEYPrivateKey *)key);
653
0
654
0
    /* Determine the hash algorithm to use, based on hashAlgTag and
655
0
     * pssParams.hashAlg; there are four cases */
656
0
    if (hashAlgTag != SEC_OID_UNKNOWN) {
657
0
        SECOidTag tag = SEC_OID_UNKNOWN;
658
0
659
0
        if (pssParams.hashAlg) {
660
0
            tag = SECOID_GetAlgorithmTag(pssParams.hashAlg);
661
0
        } else if (defaultSHA1) {
662
0
            tag = SEC_OID_SHA1;
663
0
        }
664
0
665
0
        if (tag != SEC_OID_UNKNOWN && tag != hashAlgTag) {
666
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
667
0
            return NULL;
668
0
        }
669
0
    } else if (hashAlgTag == SEC_OID_UNKNOWN) {
670
0
        if (pssParams.hashAlg) {
671
0
            hashAlgTag = SECOID_GetAlgorithmTag(pssParams.hashAlg);
672
0
        } else if (defaultSHA1) {
673
0
            hashAlgTag = SEC_OID_SHA1;
674
0
        } else {
675
0
            /* Find a suitable hash algorithm based on the NIST recommendation */
676
0
            if (modBytes <= 384) { /* 128, in NIST 800-57, Part 1 */
677
0
                hashAlgTag = SEC_OID_SHA256;
678
0
            } else if (modBytes <= 960) { /* 192, NIST 800-57, Part 1 */
679
0
                hashAlgTag = SEC_OID_SHA384;
680
0
            } else {
681
0
                hashAlgTag = SEC_OID_SHA512;
682
0
            }
683
0
        }
684
0
    }
685
0
686
0
    if (hashAlgTag != SEC_OID_SHA1 && hashAlgTag != SEC_OID_SHA224 &&
687
0
        hashAlgTag != SEC_OID_SHA256 && hashAlgTag != SEC_OID_SHA384 &&
688
0
        hashAlgTag != SEC_OID_SHA512) {
689
0
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
690
0
        return NULL;
691
0
    }
692
0
693
0
    /* Now that the hash algorithm is decided, check if it matches the
694
0
     * existing parameters if any */
695
0
    if (pssParams.maskAlg) {
696
0
        SECAlgorithmID maskHashAlg;
697
0
698
0
        if (SECOID_GetAlgorithmTag(pssParams.maskAlg) != SEC_OID_PKCS1_MGF1) {
699
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
700
0
            return NULL;
701
0
        }
702
0
703
0
        if (pssParams.maskAlg->parameters.data == NULL) {
704
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
705
0
            return NULL;
706
0
        }
707
0
708
0
        PORT_Memset(&maskHashAlg, 0, sizeof(maskHashAlg));
709
0
        rv = SEC_QuickDERDecodeItem(arena, &maskHashAlg,
710
0
                                    SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
711
0
                                    &pssParams.maskAlg->parameters);
712
0
        if (rv != SECSuccess) {
713
0
            return NULL;
714
0
        }
715
0
716
0
        /* Following the recommendation in RFC 4055, assume the hash
717
0
         * algorithm identical to pssParam.hashAlg */
718
0
        if (SECOID_GetAlgorithmTag(&maskHashAlg) != hashAlgTag) {
719
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
720
0
            return NULL;
721
0
        }
722
0
    } else if (defaultSHA1) {
723
0
        if (hashAlgTag != SEC_OID_SHA1) {
724
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
725
0
            return NULL;
726
0
        }
727
0
    }
728
0
729
0
    hashLength = HASH_ResultLenByOidTag(hashAlgTag);
730
0
731
0
    if (pssParams.saltLength.data) {
732
0
        rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.saltLength,
733
0
                                   &saltLength);
734
0
        if (rv != SECSuccess) {
735
0
            return NULL;
736
0
        }
737
0
738
0
        /* The specified salt length is too long */
739
0
        if (saltLength > modBytes - hashLength - 2) {
740
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
741
0
            return NULL;
742
0
        }
743
0
    } else if (defaultSHA1) {
744
0
        saltLength = 20;
745
0
    }
746
0
747
0
    /* Fill in the parameters */
748
0
    if (pssParams.hashAlg) {
749
0
        if (hashAlgTag == SEC_OID_SHA1) {
750
0
            /* Omit hashAlg if the the algorithm is SHA-1 (default) */
751
0
            pssParams.hashAlg = NULL;
752
0
        }
753
0
    } else {
754
0
        if (hashAlgTag != SEC_OID_SHA1) {
755
0
            pssParams.hashAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID));
756
0
            if (!pssParams.hashAlg) {
757
0
                return NULL;
758
0
            }
759
0
            rv = SECOID_SetAlgorithmID(arena, pssParams.hashAlg, hashAlgTag,
760
0
                                       NULL);
761
0
            if (rv != SECSuccess) {
762
0
                return NULL;
763
0
            }
764
0
        }
765
0
    }
766
0
767
0
    if (pssParams.maskAlg) {
768
0
        if (hashAlgTag == SEC_OID_SHA1) {
769
0
            /* Omit maskAlg if the the algorithm is SHA-1 (default) */
770
0
            pssParams.maskAlg = NULL;
771
0
        }
772
0
    } else {
773
0
        if (hashAlgTag != SEC_OID_SHA1) {
774
0
            SECItem *hashAlgItem;
775
0
776
0
            PORT_Assert(pssParams.hashAlg != NULL);
777
0
778
0
            hashAlgItem = SEC_ASN1EncodeItem(arena, NULL, pssParams.hashAlg,
779
0
                                             SEC_ASN1_GET(SECOID_AlgorithmIDTemplate));
780
0
            if (!hashAlgItem) {
781
0
                return NULL;
782
0
            }
783
0
            pssParams.maskAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID));
784
0
            if (!pssParams.maskAlg) {
785
0
                return NULL;
786
0
            }
787
0
            rv = SECOID_SetAlgorithmID(arena, pssParams.maskAlg,
788
0
                                       SEC_OID_PKCS1_MGF1, hashAlgItem);
789
0
            if (rv != SECSuccess) {
790
0
                return NULL;
791
0
            }
792
0
        }
793
0
    }
794
0
795
0
    if (pssParams.saltLength.data) {
796
0
        if (saltLength == 20) {
797
0
            /* Omit the salt length if it is the default */
798
0
            pssParams.saltLength.data = NULL;
799
0
        }
800
0
    } else {
801
0
        /* Find a suitable length from the hash algorithm and modulus bits */
802
0
        saltLength = PR_MIN(hashLength, modBytes - hashLength - 2);
803
0
804
0
        if (saltLength != 20 &&
805
0
            !SEC_ASN1EncodeInteger(arena, &pssParams.saltLength, saltLength)) {
806
0
            return NULL;
807
0
        }
808
0
    }
809
0
810
0
    if (pssParams.trailerField.data) {
811
0
        /* Omit trailerField if the value is 1 (default) */
812
0
        pssParams.trailerField.data = NULL;
813
0
    }
814
0
815
0
    return SEC_ASN1EncodeItem(arena, result,
816
0
                              &pssParams, SECKEY_RSAPSSParamsTemplate);
817
0
}
818
819
SECItem *
820
SEC_CreateSignatureAlgorithmParameters(PLArenaPool *arena,
821
                                       SECItem *result,
822
                                       SECOidTag signAlgTag,
823
                                       SECOidTag hashAlgTag,
824
                                       const SECItem *params,
825
                                       const SECKEYPrivateKey *key)
826
0
{
827
0
    switch (signAlgTag) {
828
0
        case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
829
0
            return sec_CreateRSAPSSParameters(arena, result,
830
0
                                              hashAlgTag, params, key);
831
0
832
0
        default:
833
0
            if (params == NULL)
834
0
                return NULL;
835
0
            if (result == NULL)
836
0
                result = SECITEM_AllocItem(arena, NULL, 0);
837
0
            if (SECITEM_CopyItem(arena, result, params) != SECSuccess)
838
0
                return NULL;
839
0
            return result;
840
0
    }
841
0
}