Coverage Report

Created: 2024-11-21 07:03

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