tlsprf.c (6645B)
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 { 14 return; 15 } 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(void *ctx, const unsigned char *data, 32 unsigned int data_len) 33 { 34 TLSPRFContext *cx = ctx; 35 PRUint32 bytesUsed = cx->cxKeyLen + cx->cxDataLen; 36 37 if (cx->cxRv != SECSuccess) /* function has previously failed. */ 38 return; 39 if (bytesUsed + data_len > cx->cxBufSize) { 40 /* We don't use realloc here because 41 ** (a) realloc doesn't zero out the old block, and 42 ** (b) if realloc fails, we lose the old block. 43 */ 44 PRUint32 newBufSize = bytesUsed + data_len + 512; 45 unsigned char *newBuf = (unsigned char *)PORT_Alloc(newBufSize); 46 if (!newBuf) { 47 cx->cxRv = SECFailure; 48 return; 49 } 50 PORT_Memcpy(newBuf, cx->cxBufPtr, bytesUsed); 51 if (cx->cxBufPtr != cx->cxBuf) { 52 PORT_ZFree(cx->cxBufPtr, bytesUsed); 53 } 54 cx->cxBufPtr = newBuf; 55 cx->cxBufSize = newBufSize; 56 } 57 PORT_Memcpy(cx->cxBufPtr + bytesUsed, data, data_len); 58 cx->cxDataLen += data_len; 59 } 60 61 static void 62 sftk_TLSPRFEnd(void *ctx, unsigned char *hashout, 63 unsigned int *pDigestLen, unsigned int maxDigestLen) 64 { 65 *pDigestLen = 0; /* tells Verify that no data has been input yet. */ 66 } 67 68 /* Compute the PRF values from the data previously input. */ 69 static SECStatus 70 sftk_TLSPRFUpdate(void *ctx, 71 unsigned char *sig, /* output goes here. */ 72 unsigned int *sigLen, /* how much output. */ 73 unsigned int maxLen, /* output buffer size */ 74 const unsigned char *hash, /* unused. */ 75 unsigned int hashLen) /* unused. */ 76 { 77 TLSPRFContext *cx = ctx; 78 SECStatus rv; 79 SECItem sigItem; 80 SECItem seedItem; 81 SECItem secretItem; 82 83 if (cx->cxRv != SECSuccess) 84 return cx->cxRv; 85 86 secretItem.data = cx->cxBufPtr; 87 secretItem.len = cx->cxKeyLen; 88 89 seedItem.data = cx->cxBufPtr + cx->cxKeyLen; 90 seedItem.len = cx->cxDataLen; 91 92 sigItem.data = sig; 93 if (cx->cxOutLen == 0) { 94 sigItem.len = maxLen; 95 } else if (cx->cxOutLen <= maxLen) { 96 sigItem.len = cx->cxOutLen; 97 } else { 98 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 99 return SECFailure; 100 } 101 102 if (cx->cxHashAlg != HASH_AlgNULL) { 103 rv = TLS_P_hash(cx->cxHashAlg, &secretItem, NULL, &seedItem, &sigItem, 104 cx->cxIsFIPS); 105 } else { 106 rv = TLS_PRF(&secretItem, NULL, &seedItem, &sigItem, cx->cxIsFIPS); 107 } 108 if (rv == SECSuccess && sigLen != NULL) 109 *sigLen = sigItem.len; 110 return rv; 111 } 112 113 static SECStatus 114 sftk_TLSPRFVerify(void *ctx, 115 const unsigned char *sig, /* input, for comparison. */ 116 unsigned int sigLen, /* length of sig. */ 117 const unsigned char *hash, /* data to be verified. */ 118 unsigned int hashLen) /* size of hash data. */ 119 { 120 TLSPRFContext *cx = ctx; 121 unsigned char *tmp = (unsigned char *)PORT_Alloc(sigLen); 122 unsigned int tmpLen = sigLen; 123 SECStatus rv; 124 125 if (!tmp) 126 return SECFailure; 127 if (hashLen) { 128 /* hashLen is non-zero when the user does a one-step verify. 129 ** In this case, none of the data has been input yet. 130 */ 131 sftk_TLSPRFHashUpdate(cx, hash, hashLen); 132 } 133 rv = sftk_TLSPRFUpdate(cx, tmp, &tmpLen, sigLen, NULL, 0); 134 if (rv == SECSuccess) { 135 rv = (SECStatus)(1 - !NSS_SecureMemcmp(tmp, sig, sigLen)); 136 } 137 PORT_ZFree(tmp, sigLen); 138 return rv; 139 } 140 141 static void 142 sftk_TLSPRFHashDestroy(void *ctx, PRBool freeit) 143 { 144 TLSPRFContext *cx = ctx; 145 if (freeit) { 146 if (cx->cxBufPtr != cx->cxBuf) 147 PORT_ZFree(cx->cxBufPtr, cx->cxBufSize); 148 PORT_ZFree(cx, cx->cxSize); 149 } 150 } 151 152 CK_RV 153 sftk_TLSPRFInit(SFTKSessionContext *context, 154 SFTKObject *key, 155 CK_KEY_TYPE key_type, 156 HASH_HashType hash_alg, 157 unsigned int out_len) 158 { 159 SFTKAttribute *keyVal; 160 TLSPRFContext *prf_cx; 161 CK_RV crv = CKR_HOST_MEMORY; 162 PRUint32 keySize; 163 PRUint32 blockSize; 164 165 if (key_type != CKK_GENERIC_SECRET) 166 return CKR_KEY_TYPE_INCONSISTENT; /* CKR_KEY_FUNCTION_NOT_PERMITTED */ 167 168 context->multi = PR_TRUE; 169 170 keyVal = sftk_FindAttribute(key, CKA_VALUE); 171 keySize = (!keyVal) ? 0 : keyVal->attrib.ulValueLen; 172 blockSize = keySize + sizeof(TLSPRFContext); 173 prf_cx = (TLSPRFContext *)PORT_Alloc(blockSize); 174 if (!prf_cx) 175 goto done; 176 prf_cx->cxSize = blockSize; 177 prf_cx->cxKeyLen = keySize; 178 prf_cx->cxDataLen = 0; 179 prf_cx->cxBufSize = blockSize - offsetof(TLSPRFContext, cxBuf); 180 prf_cx->cxRv = SECSuccess; 181 prf_cx->cxIsFIPS = sftk_isFIPS(key->slot->slotID); 182 prf_cx->cxBufPtr = prf_cx->cxBuf; 183 prf_cx->cxHashAlg = hash_alg; 184 prf_cx->cxOutLen = out_len; 185 if (keySize) 186 PORT_Memcpy(prf_cx->cxBufPtr, keyVal->attrib.pValue, keySize); 187 188 context->hashInfo = (void *)prf_cx; 189 context->cipherInfo = (void *)prf_cx; 190 context->hashUpdate = sftk_TLSPRFHashUpdate; 191 context->end = sftk_TLSPRFEnd; 192 context->update = sftk_TLSPRFUpdate; 193 context->verify = sftk_TLSPRFVerify; 194 context->destroy = sftk_TLSPRFNull; 195 context->hashdestroy = sftk_TLSPRFHashDestroy; 196 crv = CKR_OK; 197 198 done: 199 if (keyVal) 200 sftk_FreeAttribute(keyVal); 201 return crv; 202 }