| OLD | NEW |
| (Empty) |
| 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 #define SFTK_OFFSETOF(str, memb) ((PRPtrdiff)(&(((str *)0)->memb))) | |
| 12 | |
| 13 static void sftk_TLSPRFNull(void *data, PRBool freeit) | |
| 14 { | |
| 15 return; | |
| 16 } | |
| 17 | |
| 18 typedef struct { | |
| 19 PRUint32 cxSize; /* size of allocated block, in bytes. */ | |
| 20 PRUint32 cxBufSize; /* sizeof buffer at cxBufPtr. */ | |
| 21 unsigned char *cxBufPtr; /* points to real buffer, may be cxBuf. */ | |
| 22 PRUint32 cxKeyLen; /* bytes of cxBufPtr containing key. */ | |
| 23 PRUint32 cxDataLen; /* bytes of cxBufPtr containing data. */ | |
| 24 SECStatus cxRv; /* records failure of void functions. */ | |
| 25 PRBool cxIsFIPS; /* true if conforming to FIPS 198. */ | |
| 26 HASH_HashType cxHashAlg; /* hash algorithm to use for TLS 1.2+ */ | |
| 27 unsigned int cxOutLen; /* bytes of output if nonzero */ | |
| 28 unsigned char cxBuf[512]; /* actual size may be larger than 512. */ | |
| 29 } TLSPRFContext; | |
| 30 | |
| 31 static void | |
| 32 sftk_TLSPRFHashUpdate(TLSPRFContext *cx, const unsigned char *data, | |
| 33 unsigned int data_len) | |
| 34 { | |
| 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(TLSPRFContext *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(TLSPRFContext *cx, | |
| 71 unsigned char *sig, /* output goes here. */ | |
| 72 unsigned int * sigLen, /* how much output. */ | |
| 73 unsigned int maxLen, /* output buffer size */ | |
| 74 unsigned char *hash, /* unused. */ | |
| 75 unsigned int hashLen) /* unused. */ | |
| 76 { | |
| 77 SECStatus rv; | |
| 78 SECItem sigItem; | |
| 79 SECItem seedItem; | |
| 80 SECItem secretItem; | |
| 81 | |
| 82 if (cx->cxRv != SECSuccess) | |
| 83 return cx->cxRv; | |
| 84 | |
| 85 secretItem.data = cx->cxBufPtr; | |
| 86 secretItem.len = cx->cxKeyLen; | |
| 87 | |
| 88 seedItem.data = cx->cxBufPtr + cx->cxKeyLen; | |
| 89 seedItem.len = cx->cxDataLen; | |
| 90 | |
| 91 sigItem.data = sig; | |
| 92 if (cx->cxOutLen == 0) { | |
| 93 sigItem.len = maxLen; | |
| 94 } else if (cx->cxOutLen <= maxLen) { | |
| 95 sigItem.len = cx->cxOutLen; | |
| 96 } else { | |
| 97 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
| 98 return SECFailure; | |
| 99 } | |
| 100 | |
| 101 if (cx->cxHashAlg != HASH_AlgNULL) { | |
| 102 rv = TLS_P_hash(cx->cxHashAlg, &secretItem, NULL, &seedItem, &sigItem, | |
| 103 cx->cxIsFIPS); | |
| 104 } else { | |
| 105 rv = TLS_PRF(&secretItem, NULL, &seedItem, &sigItem, cx->cxIsFIPS); | |
| 106 } | |
| 107 if (rv == SECSuccess && sigLen != NULL) | |
| 108 *sigLen = sigItem.len; | |
| 109 return rv; | |
| 110 | |
| 111 } | |
| 112 | |
| 113 static SECStatus | |
| 114 sftk_TLSPRFVerify(TLSPRFContext *cx, | |
| 115 unsigned char *sig, /* input, for comparison. */ | |
| 116 unsigned int sigLen, /* length of sig. */ | |
| 117 unsigned char *hash, /* data to be verified. */ | |
| 118 unsigned int hashLen) /* size of hash data. */ | |
| 119 { | |
| 120 unsigned char * tmp = (unsigned char *)PORT_Alloc(sigLen); | |
| 121 unsigned int tmpLen = sigLen; | |
| 122 SECStatus rv; | |
| 123 | |
| 124 if (!tmp) | |
| 125 return SECFailure; | |
| 126 if (hashLen) { | |
| 127 /* hashLen is non-zero when the user does a one-step verify. | |
| 128 ** In this case, none of the data has been input yet. | |
| 129 */ | |
| 130 sftk_TLSPRFHashUpdate(cx, hash, hashLen); | |
| 131 } | |
| 132 rv = sftk_TLSPRFUpdate(cx, tmp, &tmpLen, sigLen, NULL, 0); | |
| 133 if (rv == SECSuccess) { | |
| 134 rv = (SECStatus)(1 - !PORT_Memcmp(tmp, sig, sigLen)); | |
| 135 } | |
| 136 PORT_ZFree(tmp, sigLen); | |
| 137 return rv; | |
| 138 } | |
| 139 | |
| 140 static void | |
| 141 sftk_TLSPRFHashDestroy(TLSPRFContext *cx, PRBool freeit) | |
| 142 { | |
| 143 if (freeit) { | |
| 144 if (cx->cxBufPtr != cx->cxBuf) | |
| 145 PORT_ZFree(cx->cxBufPtr, cx->cxBufSize); | |
| 146 PORT_ZFree(cx, cx->cxSize); | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 CK_RV | |
| 151 sftk_TLSPRFInit(SFTKSessionContext *context, | |
| 152 SFTKObject * key, | |
| 153 CK_KEY_TYPE key_type, | |
| 154 HASH_HashType hash_alg, | |
| 155 unsigned int out_len) | |
| 156 { | |
| 157 SFTKAttribute * keyVal; | |
| 158 TLSPRFContext * prf_cx; | |
| 159 CK_RV crv = CKR_HOST_MEMORY; | |
| 160 PRUint32 keySize; | |
| 161 PRUint32 blockSize; | |
| 162 | |
| 163 if (key_type != CKK_GENERIC_SECRET) | |
| 164 return CKR_KEY_TYPE_INCONSISTENT; /* CKR_KEY_FUNCTION_NOT_PERMITTED */ | |
| 165 | |
| 166 context->multi = PR_TRUE; | |
| 167 | |
| 168 keyVal = sftk_FindAttribute(key, CKA_VALUE); | |
| 169 keySize = (!keyVal) ? 0 : keyVal->attrib.ulValueLen; | |
| 170 blockSize = keySize + sizeof(TLSPRFContext); | |
| 171 prf_cx = (TLSPRFContext *)PORT_Alloc(blockSize); | |
| 172 if (!prf_cx) | |
| 173 goto done; | |
| 174 prf_cx->cxSize = blockSize; | |
| 175 prf_cx->cxKeyLen = keySize; | |
| 176 prf_cx->cxDataLen = 0; | |
| 177 prf_cx->cxBufSize = blockSize - SFTK_OFFSETOF(TLSPRFContext, cxBuf); | |
| 178 prf_cx->cxRv = SECSuccess; | |
| 179 prf_cx->cxIsFIPS = (key->slot->slotID == FIPS_SLOT_ID); | |
| 180 prf_cx->cxBufPtr = prf_cx->cxBuf; | |
| 181 prf_cx->cxHashAlg = hash_alg; | |
| 182 prf_cx->cxOutLen = out_len; | |
| 183 if (keySize) | |
| 184 PORT_Memcpy(prf_cx->cxBufPtr, keyVal->attrib.pValue, keySize); | |
| 185 | |
| 186 context->hashInfo = (void *) prf_cx; | |
| 187 context->cipherInfo = (void *) prf_cx; | |
| 188 context->hashUpdate = (SFTKHash) sftk_TLSPRFHashUpdate; | |
| 189 context->end = (SFTKEnd) sftk_TLSPRFEnd; | |
| 190 context->update = (SFTKCipher) sftk_TLSPRFUpdate; | |
| 191 context->verify = (SFTKVerify) sftk_TLSPRFVerify; | |
| 192 context->destroy = (SFTKDestroy) sftk_TLSPRFNull; | |
| 193 context->hashdestroy = (SFTKDestroy) sftk_TLSPRFHashDestroy; | |
| 194 crv = CKR_OK; | |
| 195 | |
| 196 done: | |
| 197 if (keyVal) | |
| 198 sftk_FreeAttribute(keyVal); | |
| 199 return crv; | |
| 200 } | |
| 201 | |
| OLD | NEW |