Coverage Report

Created: 2024-02-25 06:31

/src/nss/lib/softoken/tlsprf.c
Line
Count
Source (jump to first uncovered line)
1
/* tlsprf.c - TLS Pseudo Random Function (PRF) implementation
2
 *
3
 * This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "pkcs11i.h"
8
#include "blapi.h"
9
#include "secerr.h"
10
11
static void
12
sftk_TLSPRFNull(void *data, PRBool freeit)
13
12.2k
{
14
12.2k
    return;
15
12.2k
}
16
17
typedef struct {
18
    PRUint32 cxSize;          /* size of allocated block, in bytes.        */
19
    PRUint32 cxBufSize;       /* sizeof buffer at cxBufPtr.                */
20
    unsigned char *cxBufPtr;  /* points to real buffer, may be cxBuf.      */
21
    PRUint32 cxKeyLen;        /* bytes of cxBufPtr containing key.         */
22
    PRUint32 cxDataLen;       /* bytes of cxBufPtr containing data.        */
23
    SECStatus cxRv;           /* records failure of void functions.        */
24
    PRBool cxIsFIPS;          /* true if conforming to FIPS 198.           */
25
    HASH_HashType cxHashAlg;  /* hash algorithm to use for TLS 1.2+        */
26
    unsigned int cxOutLen;    /* bytes of output if nonzero                */
27
    unsigned char cxBuf[512]; /* actual size may be larger than 512.       */
28
} TLSPRFContext;
29
30
static void
31
sftk_TLSPRFHashUpdate(TLSPRFContext *cx, const unsigned char *data,
32
                      unsigned int data_len)
33
24.5k
{
34
24.5k
    PRUint32 bytesUsed = cx->cxKeyLen + cx->cxDataLen;
35
36
24.5k
    if (cx->cxRv != SECSuccess) /* function has previously failed. */
37
0
        return;
38
24.5k
    if (bytesUsed + data_len > cx->cxBufSize) {
39
        /* We don't use realloc here because
40
        ** (a) realloc doesn't zero out the old block, and
41
        ** (b) if realloc fails, we lose the old block.
42
        */
43
0
        PRUint32 newBufSize = bytesUsed + data_len + 512;
44
0
        unsigned char *newBuf = (unsigned char *)PORT_Alloc(newBufSize);
45
0
        if (!newBuf) {
46
0
            cx->cxRv = SECFailure;
47
0
            return;
48
0
        }
49
0
        PORT_Memcpy(newBuf, cx->cxBufPtr, bytesUsed);
50
0
        if (cx->cxBufPtr != cx->cxBuf) {
51
0
            PORT_ZFree(cx->cxBufPtr, bytesUsed);
52
0
        }
53
0
        cx->cxBufPtr = newBuf;
54
0
        cx->cxBufSize = newBufSize;
55
0
    }
56
24.5k
    PORT_Memcpy(cx->cxBufPtr + bytesUsed, data, data_len);
57
24.5k
    cx->cxDataLen += data_len;
58
24.5k
}
59
60
static void
61
sftk_TLSPRFEnd(TLSPRFContext *ctx, unsigned char *hashout,
62
               unsigned int *pDigestLen, unsigned int maxDigestLen)
63
12.2k
{
64
12.2k
    *pDigestLen = 0; /* tells Verify that no data has been input yet. */
65
12.2k
}
66
67
/* Compute the PRF values from the data previously input. */
68
static SECStatus
69
sftk_TLSPRFUpdate(TLSPRFContext *cx,
70
                  unsigned char *sig,   /* output goes here. */
71
                  unsigned int *sigLen, /* how much output.  */
72
                  unsigned int maxLen,  /* output buffer size */
73
                  unsigned char *hash,  /* unused. */
74
                  unsigned int hashLen) /* unused. */
75
12.2k
{
76
12.2k
    SECStatus rv;
77
12.2k
    SECItem sigItem;
78
12.2k
    SECItem seedItem;
79
12.2k
    SECItem secretItem;
80
81
12.2k
    if (cx->cxRv != SECSuccess)
82
0
        return cx->cxRv;
83
84
12.2k
    secretItem.data = cx->cxBufPtr;
85
12.2k
    secretItem.len = cx->cxKeyLen;
86
87
12.2k
    seedItem.data = cx->cxBufPtr + cx->cxKeyLen;
88
12.2k
    seedItem.len = cx->cxDataLen;
89
90
12.2k
    sigItem.data = sig;
91
12.2k
    if (cx->cxOutLen == 0) {
92
0
        sigItem.len = maxLen;
93
12.2k
    } else if (cx->cxOutLen <= maxLen) {
94
12.2k
        sigItem.len = cx->cxOutLen;
95
12.2k
    } else {
96
0
        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
97
0
        return SECFailure;
98
0
    }
99
100
12.2k
    if (cx->cxHashAlg != HASH_AlgNULL) {
101
5.74k
        rv = TLS_P_hash(cx->cxHashAlg, &secretItem, NULL, &seedItem, &sigItem,
102
5.74k
                        cx->cxIsFIPS);
103
6.54k
    } else {
104
6.54k
        rv = TLS_PRF(&secretItem, NULL, &seedItem, &sigItem, cx->cxIsFIPS);
105
6.54k
    }
106
12.2k
    if (rv == SECSuccess && sigLen != NULL)
107
12.2k
        *sigLen = sigItem.len;
108
12.2k
    return rv;
109
12.2k
}
110
111
static SECStatus
112
sftk_TLSPRFVerify(TLSPRFContext *cx,
113
                  unsigned char *sig,   /* input, for comparison. */
114
                  unsigned int sigLen,  /* length of sig.         */
115
                  unsigned char *hash,  /* data to be verified.   */
116
                  unsigned int hashLen) /* size of hash data.     */
117
0
{
118
0
    unsigned char *tmp = (unsigned char *)PORT_Alloc(sigLen);
119
0
    unsigned int tmpLen = sigLen;
120
0
    SECStatus rv;
121
122
0
    if (!tmp)
123
0
        return SECFailure;
124
0
    if (hashLen) {
125
        /* hashLen is non-zero when the user does a one-step verify.
126
        ** In this case, none of the data has been input yet.
127
        */
128
0
        sftk_TLSPRFHashUpdate(cx, hash, hashLen);
129
0
    }
130
0
    rv = sftk_TLSPRFUpdate(cx, tmp, &tmpLen, sigLen, NULL, 0);
131
0
    if (rv == SECSuccess) {
132
0
        rv = (SECStatus)(1 - !NSS_SecureMemcmp(tmp, sig, sigLen));
133
0
    }
134
0
    PORT_ZFree(tmp, sigLen);
135
0
    return rv;
136
0
}
137
138
static void
139
sftk_TLSPRFHashDestroy(TLSPRFContext *cx, PRBool freeit)
140
12.2k
{
141
12.2k
    if (freeit) {
142
12.2k
        if (cx->cxBufPtr != cx->cxBuf)
143
0
            PORT_ZFree(cx->cxBufPtr, cx->cxBufSize);
144
12.2k
        PORT_ZFree(cx, cx->cxSize);
145
12.2k
    }
146
12.2k
}
147
148
CK_RV
149
sftk_TLSPRFInit(SFTKSessionContext *context,
150
                SFTKObject *key,
151
                CK_KEY_TYPE key_type,
152
                HASH_HashType hash_alg,
153
                unsigned int out_len)
154
12.2k
{
155
12.2k
    SFTKAttribute *keyVal;
156
12.2k
    TLSPRFContext *prf_cx;
157
12.2k
    CK_RV crv = CKR_HOST_MEMORY;
158
12.2k
    PRUint32 keySize;
159
12.2k
    PRUint32 blockSize;
160
161
12.2k
    if (key_type != CKK_GENERIC_SECRET)
162
0
        return CKR_KEY_TYPE_INCONSISTENT; /* CKR_KEY_FUNCTION_NOT_PERMITTED */
163
164
12.2k
    context->multi = PR_TRUE;
165
166
12.2k
    keyVal = sftk_FindAttribute(key, CKA_VALUE);
167
12.2k
    keySize = (!keyVal) ? 0 : keyVal->attrib.ulValueLen;
168
12.2k
    blockSize = keySize + sizeof(TLSPRFContext);
169
12.2k
    prf_cx = (TLSPRFContext *)PORT_Alloc(blockSize);
170
12.2k
    if (!prf_cx)
171
0
        goto done;
172
12.2k
    prf_cx->cxSize = blockSize;
173
12.2k
    prf_cx->cxKeyLen = keySize;
174
12.2k
    prf_cx->cxDataLen = 0;
175
12.2k
    prf_cx->cxBufSize = blockSize - offsetof(TLSPRFContext, cxBuf);
176
12.2k
    prf_cx->cxRv = SECSuccess;
177
12.2k
    prf_cx->cxIsFIPS = sftk_isFIPS(key->slot->slotID);
178
12.2k
    prf_cx->cxBufPtr = prf_cx->cxBuf;
179
12.2k
    prf_cx->cxHashAlg = hash_alg;
180
12.2k
    prf_cx->cxOutLen = out_len;
181
12.2k
    if (keySize)
182
12.2k
        PORT_Memcpy(prf_cx->cxBufPtr, keyVal->attrib.pValue, keySize);
183
184
12.2k
    context->hashInfo = (void *)prf_cx;
185
12.2k
    context->cipherInfo = (void *)prf_cx;
186
12.2k
    context->hashUpdate = (SFTKHash)sftk_TLSPRFHashUpdate;
187
12.2k
    context->end = (SFTKEnd)sftk_TLSPRFEnd;
188
12.2k
    context->update = (SFTKCipher)sftk_TLSPRFUpdate;
189
12.2k
    context->verify = (SFTKVerify)sftk_TLSPRFVerify;
190
12.2k
    context->destroy = (SFTKDestroy)sftk_TLSPRFNull;
191
12.2k
    context->hashdestroy = (SFTKDestroy)sftk_TLSPRFHashDestroy;
192
12.2k
    crv = CKR_OK;
193
194
12.2k
done:
195
12.2k
    if (keyVal)
196
12.2k
        sftk_FreeAttribute(keyVal);
197
12.2k
    return crv;
198
12.2k
}