Coverage Report

Created: 2026-10-13 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/cryptohi/secsign.c
Line
Count
Source
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
#include "nss.h"
19
20
struct SGNContextStr {
21
    SECOidTag signalg;
22
    SECOidTag hashalg;
23
    CK_MECHANISM_TYPE mech;
24
    /* if we are using explicitly hashing, this value will be non-null */
25
    PK11Context *hashcx;
26
    /* if we are using the combined mechanism, this value will be non-null */
27
    PK11Context *signcx;
28
    SECKEYPrivateKey *key;
29
    SECItem mechparams;
30
};
31
32
static SGNContext *
33
sgn_NewContext(SECOidTag alg, SECItem *params, SECKEYPrivateKey *key)
34
2.71k
{
35
2.71k
    SGNContext *cx;
36
2.71k
    SECOidTag hashalg, signalg;
37
2.71k
    CK_MECHANISM_TYPE mech;
38
2.71k
    SECItem mechparams;
39
2.71k
    KeyType keyType;
40
2.71k
    PRUint32 policyFlags;
41
2.71k
    PRInt32 optFlags;
42
2.71k
    SECStatus rv;
43
44
    /* OK, map a PKCS #7 hash and encrypt algorithm into
45
     * a standard hashing algorithm. Why did we pass in the whole
46
     * PKCS #7 algTag if we were just going to change here you might
47
     * ask. Well the answer is for some cards we may have to do the
48
     * hashing on card. It may not support CKM_RSA_PKCS sign algorithm,
49
     * it may just support CKM_SHA1_RSA_PKCS and/or CKM_MD5_RSA_PKCS.
50
     */
51
    /* we have a private key, not a public key, so don't pass it in */
52
2.71k
    rv = sec_DecodeSigAlg(NULL, alg, params, &signalg, &hashalg, &mech,
53
2.71k
                          &mechparams);
54
2.71k
    if (rv != SECSuccess) {
55
0
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
56
0
        return NULL;
57
0
    }
58
2.71k
    keyType = seckey_GetKeyType(signalg);
59
60
    /* verify our key type */
61
2.71k
    if (key->keyType != keyType &&
62
1.76k
        !((key->keyType == dsaKey) && (keyType == fortezzaKey)) &&
63
1.76k
        !((key->keyType == rsaKey) && (keyType == rsaPssKey))) {
64
0
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
65
0
        goto loser;
66
0
    }
67
2.71k
    if (NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optFlags) != SECFailure) {
68
2.71k
        if (optFlags & NSS_KEY_SIZE_POLICY_SIGN_FLAG) {
69
2.71k
            rv = SECKEY_EnforceKeySize(key->keyType,
70
2.71k
                                       SECKEY_PrivateKeyStrengthInBits(key),
71
2.71k
                                       SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
72
2.71k
            if (rv != SECSuccess) {
73
0
                goto loser;
74
0
            }
75
2.71k
        }
76
2.71k
    }
77
    /* check the policy on the hash algorithm */
78
2.71k
    if ((NSS_GetAlgorithmPolicy(hashalg, &policyFlags) == SECFailure) ||
79
2.71k
        !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) {
80
0
        PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
81
0
        goto loser;
82
0
    }
83
    /* check the policy on the encryption algorithm */
84
2.71k
    if ((NSS_GetAlgorithmPolicy(signalg, &policyFlags) == SECFailure) ||
85
2.71k
        !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) {
86
0
        PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
87
0
        goto loser;
88
0
    }
89
90
2.71k
    cx = (SGNContext *)PORT_ZAlloc(sizeof(SGNContext));
91
2.71k
    if (!cx) {
92
0
        goto loser;
93
0
    }
94
2.71k
    cx->hashalg = hashalg;
95
2.71k
    cx->signalg = signalg;
96
2.71k
    cx->mech = mech;
97
2.71k
    cx->key = key;
98
2.71k
    cx->mechparams = mechparams;
99
2.71k
    return cx;
100
0
loser:
101
0
    SECITEM_FreeItem(&mechparams, PR_FALSE);
102
0
    return NULL;
103
2.71k
}
104
105
SGNContext *
106
SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key)
107
0
{
108
0
    return sgn_NewContext(alg, NULL, key);
109
0
}
110
111
SGNContext *
112
SGN_NewContextWithAlgorithmID(SECAlgorithmID *alg, SECKEYPrivateKey *key)
113
2.71k
{
114
2.71k
    SECOidTag tag = SECOID_GetAlgorithmTag(alg);
115
2.71k
    return sgn_NewContext(tag, &alg->parameters, key);
116
2.71k
}
117
118
void
119
SGN_DestroyContext(SGNContext *cx, PRBool freeit)
120
2.71k
{
121
2.71k
    if (cx) {
122
2.71k
        if (cx->hashcx != NULL) {
123
0
            PK11_DestroyContext(cx->hashcx, PR_TRUE);
124
0
            cx->hashcx = NULL;
125
0
        }
126
2.71k
        if (cx->signcx != NULL) {
127
2.71k
            PK11_DestroyContext(cx->signcx, PR_TRUE);
128
2.71k
            cx->signcx = NULL;
129
2.71k
        }
130
2.71k
        SECITEM_FreeItem(&cx->mechparams, PR_FALSE);
131
2.71k
        if (freeit) {
132
2.71k
            PORT_ZFree(cx, sizeof(SGNContext));
133
2.71k
        }
134
2.71k
    }
135
2.71k
}
136
137
static PK11Context *
138
sgn_CreateCombinedContext(SGNContext *cx)
139
2.71k
{
140
    /* the particular combination of hash and signature doesn't have a combined
141
     * mechanism, fall back to hand hash & sign */
142
2.71k
    if (cx->mech == CKM_INVALID_MECHANISM) {
143
0
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
144
0
        return NULL;
145
0
    }
146
    /* the token the private key resides in doesn't support the combined
147
     * mechanism, fall back to hand hash & sign */
148
2.71k
    if (!PK11_DoesMechanismFlag(cx->key->pkcs11Slot, cx->mech, CKF_SIGN)) {
149
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
150
0
        return NULL;
151
0
    }
152
2.71k
    return PK11_CreateContextByPrivKey(cx->mech, CKA_SIGN, cx->key,
153
2.71k
                                       &cx->mechparams);
154
2.71k
}
155
156
SECStatus
157
SGN_Begin(SGNContext *cx)
158
2.71k
{
159
2.71k
    PK11Context *signcx = NULL;
160
161
2.71k
    if (cx->hashcx != NULL) {
162
0
        PK11_DestroyContext(cx->hashcx, PR_TRUE);
163
0
        cx->hashcx = NULL;
164
0
    }
165
2.71k
    if (cx->signcx != NULL) {
166
0
        PK11_DestroyContext(cx->signcx, PR_TRUE);
167
0
        cx->signcx = NULL;
168
0
    }
169
    /* if we can get a combined context, we'll use that */
170
2.71k
    signcx = sgn_CreateCombinedContext(cx);
171
2.71k
    if (signcx != NULL) {
172
2.71k
        cx->signcx = signcx;
173
2.71k
        return SECSuccess;
174
2.71k
    }
175
176
0
    cx->hashcx = PK11_CreateDigestContext(cx->hashalg);
177
0
    if (cx->hashcx == NULL)
178
0
        return SECFailure; /* error code is already set */
179
180
0
    if (PK11_DigestBegin(cx->hashcx) != SECSuccess) {
181
0
        PK11_DestroyContext(cx->hashcx, PR_TRUE);
182
0
        cx->hashcx = NULL;
183
0
        return SECFailure; /* error code is already set */
184
0
    }
185
0
    return SECSuccess;
186
0
}
187
188
SECStatus
189
SGN_Update(SGNContext *cx, const unsigned char *input, unsigned int inputLen)
190
8.13k
{
191
8.13k
    if (cx->hashcx == NULL) {
192
8.13k
        if (cx->signcx == NULL) {
193
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
194
0
            return SECFailure;
195
0
        }
196
8.13k
        return PK11_DigestOp(cx->signcx, input, inputLen);
197
8.13k
    }
198
0
    return PK11_DigestOp(cx->hashcx, input, inputLen);
199
8.13k
}
200
201
/* XXX Old template; want to expunge it eventually. */
202
static DERTemplate SECAlgorithmIDTemplate[] = {
203
    { DER_SEQUENCE,
204
      0, NULL, sizeof(SECAlgorithmID) },
205
    { DER_OBJECT_ID,
206
      offsetof(SECAlgorithmID, algorithm) },
207
    { DER_OPTIONAL | DER_ANY,
208
      offsetof(SECAlgorithmID, parameters) },
209
    { 0 }
210
};
211
212
/*
213
 * XXX OLD Template.  Once all uses have been switched over to new one,
214
 * remove this.
215
 */
216
static DERTemplate SGNDigestInfoTemplate[] = {
217
    { DER_SEQUENCE,
218
      0, NULL, sizeof(SGNDigestInfo) },
219
    { DER_INLINE,
220
      offsetof(SGNDigestInfo, digestAlgorithm),
221
      SECAlgorithmIDTemplate },
222
    { DER_OCTET_STRING,
223
      offsetof(SGNDigestInfo, digest) },
224
    { 0 }
225
};
226
227
static SECStatus
228
sgn_allocateSignatureItem(SECKEYPrivateKey *privKey, SECItem *sigitem)
229
2.71k
{
230
2.71k
    int signatureLen;
231
2.71k
    signatureLen = PK11_SignatureLen(privKey);
232
2.71k
    if (signatureLen <= 0) {
233
0
        PORT_SetError(SEC_ERROR_INVALID_KEY);
234
0
        return SECFailure;
235
0
    }
236
2.71k
    sigitem->len = signatureLen;
237
2.71k
    sigitem->data = (unsigned char *)PORT_Alloc(signatureLen);
238
239
2.71k
    if (sigitem->data == NULL) {
240
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
241
0
        return SECFailure;
242
0
    }
243
2.71k
    return SECSuccess;
244
2.71k
}
245
246
/* Sometimes the DER signature format for the signature is different than
247
 * The PKCS #11 format for the signature. This code handles the correction
248
 * from PKCS #11 to DER */
249
static SECStatus
250
sgn_PKCS11ToX509Sig(SGNContext *cx, SECItem *sigitem)
251
2.71k
{
252
2.71k
    SECStatus rv;
253
2.71k
    SECItem result = { siBuffer, NULL, 0 };
254
255
2.71k
    if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) ||
256
2.71k
        (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) {
257
        /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */
258
948
        rv = DSAU_EncodeDerSigWithLen(&result, sigitem, sigitem->len);
259
        /* we are done with sigItem. In case of failure, we want to free
260
         * it anyway */
261
948
        SECITEM_FreeItem(sigitem, PR_FALSE);
262
948
        if (rv != SECSuccess) {
263
0
            return rv;
264
0
        }
265
948
        *sigitem = result;
266
948
    }
267
2.71k
    return SECSuccess;
268
2.71k
}
269
270
SECStatus
271
SGN_End(SGNContext *cx, SECItem *result)
272
2.71k
{
273
2.71k
    unsigned char digest[HASH_LENGTH_MAX];
274
2.71k
    unsigned int part1 = 0;
275
2.71k
    unsigned int expectedLen;
276
2.71k
    SECStatus rv;
277
2.71k
    SECItem digder, sigitem;
278
2.71k
    PLArenaPool *arena = 0;
279
2.71k
    SECKEYPrivateKey *privKey = cx->key;
280
2.71k
    SGNDigestInfo *di = 0;
281
282
2.71k
    result->data = 0;
283
2.71k
    digder.data = 0;
284
2.71k
    sigitem.data = 0;
285
286
2.71k
    if (cx->hashcx == NULL) {
287
2.71k
        if (cx->signcx == NULL) {
288
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
289
0
            return SECFailure;
290
0
        }
291
        /* if we are doing the combined hash/sign function, just finalize
292
         * the signature */
293
2.71k
        rv = sgn_allocateSignatureItem(privKey, result);
294
2.71k
        if (rv != SECSuccess) {
295
0
            return rv;
296
0
        }
297
2.71k
        rv = PK11_DigestFinal(cx->signcx, result->data, &result->len,
298
2.71k
                              result->len);
299
2.71k
        if (rv != SECSuccess) {
300
0
            SECITEM_ZfreeItem(result, PR_FALSE);
301
0
            result->data = NULL;
302
0
            return rv;
303
0
        }
304
2.71k
        return sgn_PKCS11ToX509Sig(cx, result);
305
2.71k
    }
306
    /* Finish up digest function */
307
0
    rv = PK11_DigestFinal(cx->hashcx, digest, &part1, sizeof(digest));
308
0
    if (rv != SECSuccess) {
309
0
        goto loser;
310
0
    }
311
0
    expectedLen = HASH_ResultLenByOidTag(cx->hashalg);
312
0
    if (expectedLen == 0 || part1 != expectedLen) {
313
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
314
0
        rv = SECFailure;
315
0
        goto loser;
316
0
    }
317
318
0
    if (privKey->keyType == rsaKey &&
319
0
        cx->signalg != SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
320
321
0
        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
322
0
        if (!arena) {
323
0
            rv = SECFailure;
324
0
            goto loser;
325
0
        }
326
327
        /* Construct digest info */
328
0
        di = SGN_CreateDigestInfo(cx->hashalg, digest, part1);
329
0
        if (!di) {
330
0
            rv = SECFailure;
331
0
            goto loser;
332
0
        }
333
334
        /* Der encode the digest as a DigestInfo */
335
0
        rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate,
336
0
                        di);
337
0
        if (rv != SECSuccess) {
338
0
            goto loser;
339
0
        }
340
0
    } else {
341
0
        digder.data = digest;
342
0
        digder.len = part1;
343
0
    }
344
345
    /*
346
    ** Encrypt signature after constructing appropriate PKCS#1 signature
347
    ** block
348
    */
349
0
    rv = sgn_allocateSignatureItem(privKey, &sigitem);
350
0
    if (rv != SECSuccess) {
351
0
        return rv;
352
0
    }
353
354
0
    if (cx->signalg == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
355
0
        rv = PK11_SignWithMechanism(privKey, CKM_RSA_PKCS_PSS, &cx->mechparams,
356
0
                                    &sigitem, &digder);
357
0
        if (rv != SECSuccess) {
358
0
            goto loser;
359
0
        }
360
0
    } else {
361
0
        rv = PK11_Sign(privKey, &sigitem, &digder);
362
0
        if (rv != SECSuccess) {
363
0
            goto loser;
364
0
        }
365
0
    }
366
0
    rv = sgn_PKCS11ToX509Sig(cx, &sigitem);
367
0
    *result = sigitem;
368
0
    if (rv != SECSuccess) {
369
0
        goto loser;
370
0
    }
371
0
    return SECSuccess;
372
373
0
loser:
374
0
    if (rv != SECSuccess) {
375
0
        SECITEM_FreeItem(&sigitem, PR_FALSE);
376
0
    }
377
0
    SGN_DestroyDigestInfo(di);
378
0
    if (arena != NULL) {
379
0
        PORT_FreeArena(arena, PR_FALSE);
380
0
    }
381
0
    return rv;
382
0
}
383
384
static SECStatus
385
sgn_SingleShot(SGNContext *cx, const unsigned char *input,
386
               unsigned int inputLen, SECItem *result)
387
0
{
388
0
    SECStatus rv;
389
390
0
    result->data = 0;
391
    /* if we have the combined mechanism, just do the single shot
392
     * version */
393
0
    if ((cx->mech != CKM_INVALID_MECHANISM) &&
394
0
        PK11_DoesMechanismFlag(cx->key->pkcs11Slot, cx->mech, CKF_SIGN)) {
395
0
        SECItem data = { siBuffer, (unsigned char *)input, inputLen };
396
0
        rv = sgn_allocateSignatureItem(cx->key, result);
397
0
        if (rv != SECSuccess) {
398
0
            return rv;
399
0
        }
400
0
        rv = PK11_SignWithMechanism(cx->key, cx->mech, &cx->mechparams,
401
0
                                    result, &data);
402
0
        if (rv != SECSuccess) {
403
0
            SECITEM_ZfreeItem(result, PR_FALSE);
404
0
            return rv;
405
0
        }
406
0
        return sgn_PKCS11ToX509Sig(cx, result);
407
0
    }
408
    /* fall back to the stream version */
409
0
    rv = SGN_Begin(cx);
410
0
    if (rv != SECSuccess)
411
0
        return rv;
412
413
0
    rv = SGN_Update(cx, input, inputLen);
414
0
    if (rv != SECSuccess)
415
0
        return rv;
416
417
0
    return SGN_End(cx, result);
418
0
}
419
420
/************************************************************************/
421
422
static SECStatus
423
sec_SignData(SECItem *res, const unsigned char *buf, int len,
424
             SECKEYPrivateKey *pk, SECOidTag algid, SECItem *params)
425
0
{
426
0
    SECStatus rv;
427
0
    SGNContext *sgn;
428
429
0
    sgn = sgn_NewContext(algid, params, pk);
430
431
0
    if (sgn == NULL)
432
0
        return SECFailure;
433
434
0
    rv = sgn_SingleShot(sgn, buf, len, res);
435
0
    if (rv != SECSuccess)
436
0
        goto loser;
437
438
0
loser:
439
0
    SGN_DestroyContext(sgn, PR_TRUE);
440
0
    return rv;
441
0
}
442
443
/*
444
** Sign a block of data returning in result a bunch of bytes that are the
445
** signature. Returns zero on success, an error code on failure.
446
*/
447
SECStatus
448
SEC_SignData(SECItem *res, const unsigned char *buf, int len,
449
             SECKEYPrivateKey *pk, SECOidTag algid)
450
0
{
451
0
    return sec_SignData(res, buf, len, pk, algid, NULL);
452
0
}
453
454
SECStatus
455
SEC_SignDataWithAlgorithmID(SECItem *res, const unsigned char *buf, int len,
456
                            SECKEYPrivateKey *pk, SECAlgorithmID *algid)
457
0
{
458
0
    SECOidTag tag = SECOID_GetAlgorithmTag(algid);
459
0
    return sec_SignData(res, buf, len, pk, tag, &algid->parameters);
460
0
}
461
462
/************************************************************************/
463
464
DERTemplate CERTSignedDataTemplate[] = {
465
    { DER_SEQUENCE,
466
      0, NULL, sizeof(CERTSignedData) },
467
    { DER_ANY,
468
      offsetof(CERTSignedData, data) },
469
    { DER_INLINE,
470
      offsetof(CERTSignedData, signatureAlgorithm),
471
      SECAlgorithmIDTemplate },
472
    { DER_BIT_STRING,
473
      offsetof(CERTSignedData, signature) },
474
    { 0 }
475
};
476
477
static SECOidTag
478
seckey_CurveOidFromPrivKey(const SECKEYPrivateKey *privKey)
479
0
{
480
0
    SECItem params;
481
0
    SECStatus rv;
482
0
    SECOidTag tag;
483
484
0
    rv = PK11_ReadAttribute(privKey->pkcs11Slot, privKey->pkcs11ID,
485
0
                            CKA_EC_PARAMS, NULL, &params);
486
0
    if (rv != SECSuccess) {
487
0
        return SEC_OID_UNKNOWN;
488
0
    }
489
0
    tag = SECKEY_GetECCOid(&params);
490
0
    SECITEM_FreeItem(&params, PR_FALSE);
491
0
    return tag;
492
0
}
493
494
static SECStatus
495
sec_DerSignData(PLArenaPool *arena, SECItem *result,
496
                const unsigned char *buf, int len, SECKEYPrivateKey *pk,
497
                SECOidTag algID, SECItem *params)
498
0
{
499
0
    SECItem it;
500
0
    CERTSignedData sd;
501
0
    SECStatus rv;
502
503
0
    it.data = 0;
504
505
    /* XXX We should probably have some asserts here to make sure the key type
506
     * and algID match
507
     */
508
509
0
    if (algID == SEC_OID_UNKNOWN) {
510
0
        switch (pk->keyType) {
511
0
            case rsaKey:
512
0
                algID = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
513
0
                break;
514
0
            case dsaKey:
515
                /* get Signature length (= q_len*2) and work from there */
516
0
                switch (PK11_SignatureLen(pk)) {
517
0
                    case 320:
518
0
                        algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
519
0
                        break;
520
0
                    case 448:
521
0
                        algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST;
522
0
                        break;
523
0
                    case 512:
524
0
                    default:
525
0
                        algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST;
526
0
                        break;
527
0
                }
528
0
                break;
529
0
            case ecKey:
530
0
                algID = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE;
531
0
                break;
532
0
            case edKey:
533
0
                algID = seckey_CurveOidFromPrivKey(pk);
534
0
                break;
535
0
            case mldsaKey:
536
0
                algID = seckey_GetParameterSet(pk);
537
0
                break;
538
0
            default:
539
0
                algID = SEC_OID_UNKNOWN;
540
0
                break;
541
0
        }
542
0
    }
543
0
    if (algID == SEC_OID_UNKNOWN) {
544
0
        PORT_SetError(SEC_ERROR_INVALID_KEY);
545
0
        return SECFailure;
546
0
    }
547
548
    /* Sign input buffer */
549
0
    rv = sec_SignData(&it, buf, len, pk, algID, params);
550
0
    if (rv)
551
0
        goto loser;
552
553
    /* Fill out SignedData object */
554
0
    PORT_Memset(&sd, 0, sizeof(sd));
555
0
    sd.data.data = (unsigned char *)buf;
556
0
    sd.data.len = len;
557
0
    sd.signature.data = it.data;
558
0
    sd.signature.len = it.len << 3; /* convert to bit string */
559
0
    rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, params);
560
0
    if (rv)
561
0
        goto loser;
562
563
    /* DER encode the signed data object */
564
0
    rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd);
565
    /* FALL THROUGH */
566
567
0
loser:
568
0
    PORT_Free(it.data);
569
0
    return rv;
570
0
}
571
572
SECStatus
573
SEC_DerSignData(PLArenaPool *arena, SECItem *result,
574
                const unsigned char *buf, int len, SECKEYPrivateKey *pk,
575
                SECOidTag algID)
576
0
{
577
0
    return sec_DerSignData(arena, result, buf, len, pk, algID, NULL);
578
0
}
579
580
SECStatus
581
SEC_DerSignDataWithAlgorithmID(PLArenaPool *arena, SECItem *result,
582
                               const unsigned char *buf, int len,
583
                               SECKEYPrivateKey *pk,
584
                               SECAlgorithmID *algID)
585
0
{
586
0
    SECOidTag tag = SECOID_GetAlgorithmTag(algID);
587
0
    return sec_DerSignData(arena, result, buf, len, pk, tag, &algID->parameters);
588
0
}
589
590
SECStatus
591
SGN_Digest(SECKEYPrivateKey *privKey,
592
           SECOidTag algtag, SECItem *result, SECItem *digest)
593
25.2k
{
594
25.2k
    int modulusLen;
595
25.2k
    SECStatus rv;
596
25.2k
    SECItem digder;
597
25.2k
    PLArenaPool *arena = 0;
598
25.2k
    SGNDigestInfo *di = 0;
599
25.2k
    SECOidTag enctag;
600
25.2k
    PRUint32 policyFlags;
601
25.2k
    PRInt32 optFlags;
602
603
25.2k
    result->data = 0;
604
605
25.2k
    if (NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optFlags) != SECFailure) {
606
25.2k
        if (optFlags & NSS_KEY_SIZE_POLICY_SIGN_FLAG) {
607
25.2k
            rv = SECKEY_EnforceKeySize(privKey->keyType,
608
25.2k
                                       SECKEY_PrivateKeyStrengthInBits(privKey),
609
25.2k
                                       SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
610
25.2k
            if (rv != SECSuccess) {
611
0
                return SECFailure;
612
0
            }
613
25.2k
        }
614
25.2k
    }
615
    /* check the policy on the hash algorithm */
616
25.2k
    if ((NSS_GetAlgorithmPolicy(algtag, &policyFlags) == SECFailure) ||
617
25.2k
        !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) {
618
0
        PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
619
0
        return SECFailure;
620
0
    }
621
622
25.2k
    if ((privKey->keyType == mldsaKey) || (privKey->keyType == edKey)) {
623
        /* don't allow digest sign for mldsa. May be possible if mu
624
         * is enabled, in that case the hash must be the special mldsa
625
         * hash, which we don't have defined yet */
626
0
        PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
627
0
        return SECFailure;
628
0
    }
629
    /* check the policy on the encryption algorithm */
630
25.2k
    enctag = sec_GetEncAlgFromSigAlg(
631
25.2k
        SEC_GetSignatureAlgorithmOidTagByKey(privKey, NULL, algtag));
632
25.2k
    if ((enctag == SEC_OID_UNKNOWN) ||
633
25.2k
        (NSS_GetAlgorithmPolicy(enctag, &policyFlags) == SECFailure) ||
634
25.2k
        !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) {
635
0
        PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
636
0
        return SECFailure;
637
0
    }
638
639
25.2k
    if (privKey->keyType == rsaKey) {
640
641
19.6k
        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
642
19.6k
        if (!arena) {
643
0
            rv = SECFailure;
644
0
            goto loser;
645
0
        }
646
647
        /* Construct digest info */
648
19.6k
        di = SGN_CreateDigestInfo(algtag, digest->data, digest->len);
649
19.6k
        if (!di) {
650
0
            rv = SECFailure;
651
0
            goto loser;
652
0
        }
653
654
        /* Der encode the digest as a DigestInfo */
655
19.6k
        rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate,
656
19.6k
                        di);
657
19.6k
        if (rv != SECSuccess) {
658
0
            goto loser;
659
0
        }
660
19.6k
    } else {
661
5.62k
        digder.data = digest->data;
662
5.62k
        digder.len = digest->len;
663
5.62k
    }
664
665
    /*
666
    ** Encrypt signature after constructing appropriate PKCS#1 signature
667
    ** block
668
    */
669
25.2k
    modulusLen = PK11_SignatureLen(privKey);
670
25.2k
    if (modulusLen <= 0) {
671
0
        PORT_SetError(SEC_ERROR_INVALID_KEY);
672
0
        rv = SECFailure;
673
0
        goto loser;
674
0
    }
675
25.2k
    result->len = modulusLen;
676
25.2k
    result->data = (unsigned char *)PORT_Alloc(modulusLen);
677
25.2k
    result->type = siBuffer;
678
679
25.2k
    if (result->data == NULL) {
680
0
        rv = SECFailure;
681
0
        goto loser;
682
0
    }
683
684
25.2k
    rv = PK11_Sign(privKey, result, &digder);
685
25.2k
    if (rv != SECSuccess) {
686
0
        PORT_Free(result->data);
687
0
        result->data = NULL;
688
0
    }
689
690
25.2k
loser:
691
25.2k
    SGN_DestroyDigestInfo(di);
692
25.2k
    if (arena != NULL) {
693
19.6k
        PORT_FreeArena(arena, PR_FALSE);
694
19.6k
    }
695
25.2k
    return rv;
696
25.2k
}
697
698
SECOidTag
699
SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag)
700
25.2k
{
701
25.2k
    SECOidTag sigTag = SEC_OID_UNKNOWN;
702
703
25.2k
    switch (keyType) {
704
0
        case rsaPssKey:
705
0
            sigTag = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
706
0
            break;
707
19.6k
        case rsaKey:
708
19.6k
            switch (hashAlgTag) {
709
0
                case SEC_OID_MD2:
710
0
                    sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
711
0
                    break;
712
0
                case SEC_OID_MD5:
713
0
                    sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
714
0
                    break;
715
17.8k
                case SEC_OID_SHA1:
716
17.8k
                    sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
717
17.8k
                    break;
718
0
                case SEC_OID_SHA224:
719
0
                    sigTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION;
720
0
                    break;
721
0
                case SEC_OID_UNKNOWN: /* default for RSA if not specified */
722
248
                case SEC_OID_SHA256:
723
248
                    sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
724
248
                    break;
725
462
                case SEC_OID_SHA384:
726
462
                    sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
727
462
                    break;
728
1.06k
                case SEC_OID_SHA512:
729
1.06k
                    sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
730
1.06k
                    break;
731
0
                default:
732
0
                    break;
733
19.6k
            }
734
19.6k
            break;
735
19.6k
        case dsaKey:
736
0
            switch (hashAlgTag) {
737
0
                case SEC_OID_SHA1:
738
0
                    sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
739
0
                    break;
740
0
                case SEC_OID_SHA224:
741
0
                    sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST;
742
0
                    break;
743
0
                case SEC_OID_UNKNOWN: /* default for DSA if not specified */
744
0
                case SEC_OID_SHA256:
745
0
                    sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST;
746
0
                    break;
747
0
                default:
748
0
                    break;
749
0
            }
750
0
            break;
751
0
        case mldsaKey:
752
0
            switch (hashAlgTag) {
753
0
                case SEC_OID_ML_DSA_44:
754
0
                case SEC_OID_ML_DSA_65:
755
0
                case SEC_OID_ML_DSA_87:
756
                    /* only accept known mldsa values. For mldsa, the hash must
757
                     * match the underlying signature algorithm */
758
0
                    sigTag = hashAlgTag;
759
0
                    break;
760
0
                default:
761
0
                    break;
762
0
            }
763
0
            break;
764
5.62k
        case ecKey:
765
5.62k
            switch (hashAlgTag) {
766
4.49k
                case SEC_OID_SHA1:
767
4.49k
                    sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE;
768
4.49k
                    break;
769
0
                case SEC_OID_SHA224:
770
0
                    sigTag = SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE;
771
0
                    break;
772
0
                case SEC_OID_UNKNOWN: /* default for ECDSA if not specified */
773
304
                case SEC_OID_SHA256:
774
304
                    sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE;
775
304
                    break;
776
33
                case SEC_OID_SHA384:
777
33
                    sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE;
778
33
                    break;
779
789
                case SEC_OID_SHA512:
780
789
                    sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE;
781
789
                    break;
782
0
                default:
783
0
                    break;
784
5.62k
            }
785
5.62k
            break;
786
5.62k
        case edKey:
787
            /* signature and curve are the same oid, just make sure
788
             * it's valid */
789
0
            switch (hashAlgTag) {
790
0
                case SEC_OID_ED25519_SIGNATURE:
791
                    /* add curve 448 here if/when we to support it */
792
0
                    sigTag = hashAlgTag;
793
0
                    break;
794
0
                default:
795
0
                    break;
796
0
            }
797
0
            break;
798
0
        default:
799
0
            break;
800
25.2k
    }
801
25.2k
    return sigTag;
802
25.2k
}
803
804
SECOidTag
805
SEC_GetSignatureAlgorithmOidTagByKey(const SECKEYPrivateKey *privKey, const SECKEYPublicKey *pubKey, SECOidTag hashAlgTag)
806
25.2k
{
807
25.2k
    KeyType keyType = nullKey;
808
    /* make sure we have a key */
809
25.2k
    if ((privKey && pubKey) || (!privKey && !pubKey)) {
810
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
811
0
        return SEC_OID_UNKNOWN;
812
0
    }
813
    /* make sure we have only one key */
814
25.2k
    if (privKey) {
815
25.2k
        keyType = privKey->keyType;
816
25.2k
        switch (keyType) {
817
0
            case mldsaKey:
818
                /* for mldsa, the hash has to match the paramset anyway, so
819
                 * pass in the param set as the hash */
820
0
                hashAlgTag = seckey_GetParameterSet(privKey);
821
0
                break;
822
0
            case edKey:
823
                /* for ed, hash matches the curve, so we return the curve oid */
824
0
                hashAlgTag = seckey_CurveOidFromPrivKey(privKey);
825
0
                break;
826
25.2k
            default:
827
                /* everything gets the hash from the caller, or will default */
828
25.2k
                break;
829
25.2k
        }
830
25.2k
    } else {
831
        /* the logic above should guarentee the following assert. */
832
0
        PORT_Assert(pubKey != NULL);
833
0
        PORT_Assert(privKey == NULL);
834
0
        keyType = pubKey->keyType;
835
0
        switch (keyType) {
836
0
            case mldsaKey:
837
                /* for mldsa, the hash has to match the paramset anyway, so
838
                 * pass in the param set as the hash */
839
0
                hashAlgTag = pubKey->u.mldsa.paramSet;
840
0
                break;
841
0
            case edKey:
842
                /* for ed, hash matches the curve, so we return the curve oid */
843
0
                hashAlgTag = SECKEY_GetECCOid(&pubKey->u.ec.DEREncodedParams);
844
0
                break;
845
0
            default:
846
                /* everything gets the hash from the caller, or will default */
847
0
                break;
848
0
        }
849
0
    }
850
25.2k
    return SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
851
25.2k
}
852
853
SECItem *
854
sec_CreateRSAPSSParameters(PLArenaPool *arena,
855
                           SECItem *result,
856
                           SECOidTag hashAlgTag,
857
                           const SECItem *params,
858
                           int modBytes)
859
1.76k
{
860
1.76k
    SECKEYRSAPSSParams pssParams;
861
1.76k
    int hashLength;
862
1.76k
    unsigned long saltLength;
863
1.76k
    PRBool defaultSHA1 = PR_FALSE;
864
1.76k
    SECStatus rv;
865
866
1.76k
    PORT_Memset(&pssParams, 0, sizeof(pssParams));
867
868
1.76k
    if (params && params->data) {
869
        /* The parameters field should either be empty or contain
870
         * valid RSA-PSS parameters */
871
0
        PORT_Assert(!(params->len == 2 &&
872
0
                      params->data[0] == SEC_ASN1_NULL &&
873
0
                      params->data[1] == 0));
874
0
        rv = SEC_QuickDERDecodeItem(arena, &pssParams,
875
0
                                    SECKEY_RSAPSSParamsTemplate,
876
0
                                    params);
877
0
        if (rv != SECSuccess) {
878
0
            return NULL;
879
0
        }
880
0
        defaultSHA1 = PR_TRUE;
881
0
    }
882
883
1.76k
    if (pssParams.trailerField.data) {
884
0
        unsigned long trailerField;
885
886
0
        rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.trailerField,
887
0
                                   &trailerField);
888
0
        if (rv != SECSuccess) {
889
0
            return NULL;
890
0
        }
891
0
        if (trailerField != 1) {
892
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
893
0
            return NULL;
894
0
        }
895
0
    }
896
897
    /* Determine the hash algorithm to use, based on hashAlgTag and
898
     * pssParams.hashAlg; there are 6  cases.
899
     *  case:
900
     *  1) We have params and params.hashAlg and we have a specified hashAlgTag,
901
     *  make sure that hashAlgTag specified by the appication matches.
902
     *  2) We have params, but no params.hashAlg and we have a specified
903
     *  hashAlg, make sure the hashAlgTag matches SEC_OID_SHA1.
904
     *  3) we did not specify any parameters but we did specified
905
     *  a hashAlgTag. Use the specified hash algtag.
906
     *  4) We have params and params.hashAlg and we did not specify a
907
     *  hashAlgTag, use the hashAlg from the parameter.
908
     *  5) We have params, but no params.hashAlg and we did not specify a
909
     *  hashAlgTag, use the SEC_OID_SHA1
910
     *  6) We did not specify any parameters, nor did we specify a
911
     *  hashAlgTag, use the key size to select an appropriate hashAlg.
912
     */
913
1.76k
    if (hashAlgTag != SEC_OID_UNKNOWN) {
914
1.76k
        SECOidTag tag = SEC_OID_UNKNOWN;
915
916
1.76k
        if (pssParams.hashAlg) {
917
0
            tag = SECOID_GetAlgorithmTag(pssParams.hashAlg);
918
1.76k
        } else if (defaultSHA1) {
919
0
            tag = SEC_OID_SHA1;
920
0
        }
921
922
1.76k
        if (tag != SEC_OID_UNKNOWN && tag != hashAlgTag) {
923
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
924
0
            return NULL;
925
0
        }
926
1.76k
    } else if (hashAlgTag == SEC_OID_UNKNOWN) {
927
0
        if (pssParams.hashAlg) {
928
0
            hashAlgTag = SECOID_GetAlgorithmTag(pssParams.hashAlg);
929
0
        } else if (defaultSHA1) {
930
0
            hashAlgTag = SEC_OID_SHA1;
931
0
        } else {
932
            /* Find a suitable hash algorithm based on the NIST recommendation */
933
0
            if (modBytes <= 384) { /* 128, in NIST 800-57, Part 1 */
934
0
                hashAlgTag = SEC_OID_SHA256;
935
0
            } else if (modBytes <= 960) { /* 192, NIST 800-57, Part 1 */
936
0
                hashAlgTag = SEC_OID_SHA384;
937
0
            } else {
938
0
                hashAlgTag = SEC_OID_SHA512;
939
0
            }
940
0
        }
941
0
    }
942
943
    /* explicitly restrict hashAlg to SHA2 variants */
944
1.76k
    if (hashAlgTag != SEC_OID_SHA1 && hashAlgTag != SEC_OID_SHA224 &&
945
1.76k
        hashAlgTag != SEC_OID_SHA256 && hashAlgTag != SEC_OID_SHA384 &&
946
464
        hashAlgTag != SEC_OID_SHA512) {
947
0
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
948
0
        return NULL;
949
0
    }
950
951
    /* Now that the hash algorithm is decided, check if it matches the
952
     * existing parameters if any */
953
1.76k
    if (pssParams.maskAlg) {
954
0
        SECAlgorithmID maskHashAlg;
955
956
0
        if (SECOID_GetAlgorithmTag(pssParams.maskAlg) != SEC_OID_PKCS1_MGF1) {
957
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
958
0
            return NULL;
959
0
        }
960
961
0
        if (pssParams.maskAlg->parameters.data == NULL) {
962
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
963
0
            return NULL;
964
0
        }
965
966
0
        PORT_Memset(&maskHashAlg, 0, sizeof(maskHashAlg));
967
0
        rv = SEC_QuickDERDecodeItem(arena, &maskHashAlg,
968
0
                                    SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
969
0
                                    &pssParams.maskAlg->parameters);
970
0
        if (rv != SECSuccess) {
971
0
            return NULL;
972
0
        }
973
974
        /* Following the recommendation in RFC 4055, assume the hash
975
         * algorithm identical to pssParam.hashAlg */
976
0
        if (SECOID_GetAlgorithmTag(&maskHashAlg) != hashAlgTag) {
977
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
978
0
            return NULL;
979
0
        }
980
1.76k
    } else if (defaultSHA1) {
981
0
        if (hashAlgTag != SEC_OID_SHA1) {
982
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
983
0
            return NULL;
984
0
        }
985
0
    }
986
987
1.76k
    hashLength = HASH_ResultLenByOidTag(hashAlgTag);
988
989
1.76k
    if (modBytes < hashLength + 2) {
990
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
991
0
        return NULL;
992
0
    }
993
994
1.76k
    if (pssParams.saltLength.data) {
995
0
        rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.saltLength,
996
0
                                   &saltLength);
997
0
        if (rv != SECSuccess) {
998
0
            return NULL;
999
0
        }
1000
1001
        /* The specified salt length is too long */
1002
0
        if (saltLength > (unsigned long)(modBytes - hashLength - 2)) {
1003
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
1004
0
            return NULL;
1005
0
        }
1006
1.76k
    } else if (defaultSHA1) {
1007
0
        saltLength = 20;
1008
0
    }
1009
1010
    /* Fill in the parameters */
1011
1.76k
    if (pssParams.hashAlg) {
1012
0
        if (hashAlgTag == SEC_OID_SHA1) {
1013
            /* Omit hashAlg if the the algorithm is SHA-1 (default) */
1014
0
            pssParams.hashAlg = NULL;
1015
0
        }
1016
1.76k
    } else {
1017
1.76k
        if (hashAlgTag != SEC_OID_SHA1) {
1018
1.76k
            pssParams.hashAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID));
1019
1.76k
            if (!pssParams.hashAlg) {
1020
0
                return NULL;
1021
0
            }
1022
1.76k
            rv = SECOID_SetAlgorithmID(arena, pssParams.hashAlg, hashAlgTag,
1023
1.76k
                                       NULL);
1024
1.76k
            if (rv != SECSuccess) {
1025
0
                return NULL;
1026
0
            }
1027
1.76k
        }
1028
1.76k
    }
1029
1030
1.76k
    if (pssParams.maskAlg) {
1031
0
        if (hashAlgTag == SEC_OID_SHA1) {
1032
            /* Omit maskAlg if the the algorithm is SHA-1 (default) */
1033
0
            pssParams.maskAlg = NULL;
1034
0
        }
1035
1.76k
    } else {
1036
1.76k
        if (hashAlgTag != SEC_OID_SHA1) {
1037
1.76k
            SECItem *hashAlgItem;
1038
1039
1.76k
            PORT_Assert(pssParams.hashAlg != NULL);
1040
1041
1.76k
            hashAlgItem = SEC_ASN1EncodeItem(arena, NULL, pssParams.hashAlg,
1042
1.76k
                                             SEC_ASN1_GET(SECOID_AlgorithmIDTemplate));
1043
1.76k
            if (!hashAlgItem) {
1044
0
                return NULL;
1045
0
            }
1046
1.76k
            pssParams.maskAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID));
1047
1.76k
            if (!pssParams.maskAlg) {
1048
0
                return NULL;
1049
0
            }
1050
1.76k
            rv = SECOID_SetAlgorithmID(arena, pssParams.maskAlg,
1051
1.76k
                                       SEC_OID_PKCS1_MGF1, hashAlgItem);
1052
1.76k
            if (rv != SECSuccess) {
1053
0
                return NULL;
1054
0
            }
1055
1.76k
        }
1056
1.76k
    }
1057
1058
1.76k
    if (pssParams.saltLength.data) {
1059
0
        if (saltLength == 20) {
1060
            /* Omit the salt length if it is the default */
1061
0
            pssParams.saltLength.data = NULL;
1062
0
        }
1063
1.76k
    } else {
1064
        /* Find a suitable length from the hash algorithm and modulus bits */
1065
1.76k
        saltLength = PR_MIN(hashLength, modBytes - hashLength - 2);
1066
1067
1.76k
        if (saltLength != 20 &&
1068
1.76k
            !SEC_ASN1EncodeInteger(arena, &pssParams.saltLength, saltLength)) {
1069
0
            return NULL;
1070
0
        }
1071
1.76k
    }
1072
1073
1.76k
    if (pssParams.trailerField.data) {
1074
        /* Omit trailerField if the value is 1 (default) */
1075
0
        pssParams.trailerField.data = NULL;
1076
0
    }
1077
1078
1.76k
    return SEC_ASN1EncodeItem(arena, result,
1079
1.76k
                              &pssParams, SECKEY_RSAPSSParamsTemplate);
1080
1.76k
}
1081
1082
SECItem *
1083
SEC_CreateRSAPSSParameters(PLArenaPool *arena,
1084
                           SECItem *result,
1085
                           SECOidTag hashAlgTag,
1086
                           const SECItem *params,
1087
                           const SECKEYPrivateKey *privKey,
1088
                           const SECKEYPublicKey *pubKey)
1089
1.76k
{
1090
    /* if no keys are provided arrange for the saltLength to be hashLen */
1091
1.76k
    int modBytes = (HASH_LENGTH_MAX * 2) + 2;
1092
1093
    /* we don't need all these parameters, but we should have at least
1094
     * one of these */
1095
1.76k
    if (!privKey && !pubKey && !params && (hashAlgTag == SEC_OID_UNKNOWN)) {
1096
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1097
0
        return NULL;
1098
0
    }
1099
    /* only allow one key */
1100
1.76k
    if (privKey && pubKey) {
1101
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1102
0
        return NULL;
1103
0
    }
1104
1.76k
    if (privKey) {
1105
1.76k
        if (privKey->keyType != rsaKey && privKey->keyType != rsaPssKey) {
1106
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
1107
0
            return NULL;
1108
0
        }
1109
        /* cast away the const, even though it's still logically a const
1110
         * function */
1111
1.76k
        modBytes = PK11_GetPrivateModulusLen((SECKEYPrivateKey *)privKey);
1112
1.76k
    } else if (pubKey) {
1113
0
        if (pubKey->keyType != rsaKey && pubKey->keyType != rsaPssKey) {
1114
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
1115
0
            return NULL;
1116
0
        }
1117
0
        modBytes = pubKey->u.rsa.modulus.len;
1118
0
    }
1119
1.76k
    return sec_CreateRSAPSSParameters(arena, result, hashAlgTag,
1120
1.76k
                                      params, modBytes);
1121
1.76k
}
1122
1123
SECItem *
1124
SEC_CreateSignatureAlgorithmParameters(PLArenaPool *arena,
1125
                                       SECItem *result,
1126
                                       SECOidTag signAlgTag,
1127
                                       SECOidTag hashAlgTag,
1128
                                       const SECItem *params,
1129
                                       const SECKEYPrivateKey *key)
1130
2.71k
{
1131
2.71k
    PORT_SetError(0);
1132
2.71k
    switch (signAlgTag) {
1133
1.76k
        case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
1134
1.76k
            return SEC_CreateRSAPSSParameters(arena, result,
1135
1.76k
                                              hashAlgTag, params, key, NULL);
1136
1137
948
        default:
1138
948
            if (params == NULL)
1139
948
                return NULL;
1140
0
            if (result == NULL)
1141
0
                result = SECITEM_AllocItem(arena, NULL, 0);
1142
0
            if (result == NULL) {
1143
0
                return NULL;
1144
0
            }
1145
0
            if (SECITEM_CopyItem(arena, result, params) != SECSuccess)
1146
0
                return NULL;
1147
0
            return result;
1148
2.71k
    }
1149
2.71k
}
1150
1151
SECItem *
1152
SEC_CreateVerifyAlgorithmParameters(PLArenaPool *arena,
1153
                                    SECItem *result,
1154
                                    SECOidTag signAlgTag,
1155
                                    SECOidTag hashAlgTag,
1156
                                    const SECItem *params,
1157
                                    const SECKEYPublicKey *key)
1158
0
{
1159
0
    PORT_SetError(0);
1160
0
    switch (signAlgTag) {
1161
0
        case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
1162
0
            return SEC_CreateRSAPSSParameters(arena, result,
1163
0
                                              hashAlgTag, params, NULL, key);
1164
1165
0
        default:
1166
0
            if (params == NULL)
1167
0
                return NULL;
1168
0
            if (result == NULL)
1169
0
                result = SECITEM_AllocItem(arena, NULL, 0);
1170
0
            if (result == NULL) {
1171
0
                return NULL;
1172
0
            }
1173
0
            if (SECITEM_CopyItem(arena, result, params) != SECSuccess)
1174
0
                return NULL;
1175
0
            return result;
1176
0
    }
1177
0
}
1178
1179
SECStatus
1180
SEC_CreateSignatureAlgorithmID(PLArenaPool *arena,
1181
                               SECAlgorithmID *signAlgID,
1182
                               SECOidTag signAlgTag,
1183
                               SECOidTag hashAlgTag,
1184
                               const SECItem *params,
1185
                               const SECKEYPrivateKey *privKey,
1186
                               const SECKEYPublicKey *pubKey)
1187
2.71k
{
1188
2.71k
    SECItem *newParams = NULL;
1189
1190
2.71k
    if (signAlgTag == SEC_OID_UNKNOWN) {
1191
0
        signAlgTag = SEC_GetSignatureAlgorithmOidTagByKey(privKey, pubKey,
1192
0
                                                          hashAlgTag);
1193
2.71k
    } else {
1194
        /* SEC_GetSignatureAlgorithm already checks if privKey and pubKey
1195
         * is present and the only case */
1196
2.71k
        if ((privKey && pubKey) || (!privKey && !pubKey)) {
1197
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
1198
0
            return SECFailure;
1199
0
        }
1200
2.71k
    }
1201
1202
2.71k
    if (signAlgTag == SEC_OID_UNKNOWN) {
1203
        /* error already set by SEC_GetSignatureAlgorithmOidTagByKey */
1204
0
        return SECFailure;
1205
0
    }
1206
1207
2.71k
    if (privKey) {
1208
2.71k
        newParams = SEC_CreateSignatureAlgorithmParameters(arena, NULL,
1209
2.71k
                                                           signAlgTag,
1210
2.71k
                                                           hashAlgTag,
1211
2.71k
                                                           params,
1212
2.71k
                                                           privKey);
1213
2.71k
    } else {
1214
        /* must be pubKey */
1215
0
        newParams = SEC_CreateVerifyAlgorithmParameters(arena, NULL,
1216
0
                                                        signAlgTag,
1217
0
                                                        hashAlgTag,
1218
0
                                                        params,
1219
0
                                                        pubKey);
1220
0
    }
1221
1222
    /* It's legal (and common) for params to be NULL; look at the error
1223
     * code to see if there was a failure */
1224
2.71k
    if (!newParams && PORT_GetError() != 0) {
1225
0
        return SECFailure;
1226
0
    }
1227
1228
2.71k
    return SECOID_SetAlgorithmID(arena, signAlgID, signAlgTag, newParams);
1229
2.71k
}