jpakesftk.c (12157B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "seccomon.h" 6 #include "secerr.h" 7 #include "blapi.h" 8 #include "pkcs11i.h" 9 #include "softoken.h" 10 11 static CK_RV 12 jpake_mapStatus(SECStatus rv, CK_RV invalidArgsMapping) 13 { 14 int err; 15 if (rv == SECSuccess) 16 return CKR_OK; 17 err = PORT_GetError(); 18 switch (err) { 19 /* XXX: SEC_ERROR_INVALID_ARGS might be caused by invalid template 20 parameters. */ 21 case SEC_ERROR_INVALID_ARGS: 22 return invalidArgsMapping; 23 case SEC_ERROR_BAD_SIGNATURE: 24 return CKR_SIGNATURE_INVALID; 25 case SEC_ERROR_NO_MEMORY: 26 return CKR_HOST_MEMORY; 27 } 28 return CKR_FUNCTION_FAILED; 29 } 30 31 /* If key is not NULL then the gx value will be stored as an attribute with 32 the type given by the gxAttrType parameter. */ 33 static CK_RV 34 jpake_Sign(PLArenaPool *arena, const PQGParams *pqg, HASH_HashType hashType, 35 const SECItem *signerID, const SECItem *x, 36 CK_NSS_JPAKEPublicValue *out) 37 { 38 SECItem gx, gv, r; 39 CK_RV crv; 40 41 PORT_Assert(arena != NULL); 42 43 gx.data = NULL; 44 gv.data = NULL; 45 r.data = NULL; 46 crv = jpake_mapStatus(JPAKE_Sign(arena, pqg, hashType, signerID, x, NULL, 47 NULL, &gx, &gv, &r), 48 CKR_MECHANISM_PARAM_INVALID); 49 if (crv == CKR_OK) { 50 if ((out->pGX != NULL && out->ulGXLen >= gx.len) && 51 (out->pGV != NULL && out->ulGVLen >= gv.len) && 52 (out->pR != NULL && out->ulRLen >= r.len)) { 53 PORT_Memcpy(out->pGX, gx.data, gx.len); 54 PORT_Memcpy(out->pGV, gv.data, gv.len); 55 PORT_Memcpy(out->pR, r.data, r.len); 56 out->ulGXLen = gx.len; 57 out->ulGVLen = gv.len; 58 out->ulRLen = r.len; 59 } else { 60 crv = CKR_MECHANISM_PARAM_INVALID; 61 } 62 } 63 return crv; 64 } 65 66 static CK_RV 67 jpake_Verify(PLArenaPool *arena, const PQGParams *pqg, 68 HASH_HashType hashType, const SECItem *signerID, 69 const CK_BYTE *peerIDData, CK_ULONG peerIDLen, 70 const CK_NSS_JPAKEPublicValue *publicValueIn) 71 { 72 SECItem peerID, gx, gv, r; 73 peerID.data = (unsigned char *)peerIDData; 74 peerID.len = peerIDLen; 75 gx.data = publicValueIn->pGX; 76 gx.len = publicValueIn->ulGXLen; 77 gv.data = publicValueIn->pGV; 78 gv.len = publicValueIn->ulGVLen; 79 r.data = publicValueIn->pR; 80 r.len = publicValueIn->ulRLen; 81 return jpake_mapStatus(JPAKE_Verify(arena, pqg, hashType, signerID, &peerID, 82 &gx, &gv, &r), 83 CKR_MECHANISM_PARAM_INVALID); 84 } 85 86 #define NUM_ELEM(x) (sizeof(x) / sizeof(x)[0]) 87 88 /* If the template has the key type set, ensure that it was set to the correct 89 * value. If the template did not have the key type set, set it to the 90 * correct value. 91 */ 92 static CK_RV 93 jpake_enforceKeyType(SFTKObject *key, CK_KEY_TYPE keyType) 94 { 95 CK_RV crv; 96 SFTKAttribute *keyTypeAttr = sftk_FindAttribute(key, CKA_KEY_TYPE); 97 if (keyTypeAttr != NULL) { 98 crv = *(CK_KEY_TYPE *)keyTypeAttr->attrib.pValue == keyType 99 ? CKR_OK 100 : CKR_TEMPLATE_INCONSISTENT; 101 sftk_FreeAttribute(keyTypeAttr); 102 } else { 103 crv = sftk_forceAttribute(key, CKA_KEY_TYPE, &keyType, sizeof keyType); 104 } 105 return crv; 106 } 107 108 static CK_RV 109 jpake_MultipleSecItem2Attribute(SFTKObject *key, const SFTKItemTemplate *attrs, 110 size_t attrsCount) 111 { 112 size_t i; 113 114 for (i = 0; i < attrsCount; ++i) { 115 CK_RV crv = sftk_forceAttribute(key, attrs[i].type, attrs[i].item->data, 116 attrs[i].item->len); 117 if (crv != CKR_OK) 118 return crv; 119 } 120 return CKR_OK; 121 } 122 123 CK_RV 124 jpake_Round1(HASH_HashType hashType, CK_NSS_JPAKERound1Params *params, 125 SFTKObject *key) 126 { 127 CK_RV crv; 128 PQGParams pqg; 129 PLArenaPool *arena; 130 SECItem signerID; 131 SFTKItemTemplate templateAttrs[] = { 132 { CKA_PRIME, &pqg.prime }, 133 { CKA_SUBPRIME, &pqg.subPrime }, 134 { CKA_BASE, &pqg.base }, 135 { CKA_NSS_JPAKE_SIGNERID, &signerID } 136 }; 137 SECItem x2, gx1, gx2; 138 const SFTKItemTemplate generatedAttrs[] = { 139 { CKA_NSS_JPAKE_X2, &x2 }, 140 { CKA_NSS_JPAKE_GX1, &gx1 }, 141 { CKA_NSS_JPAKE_GX2, &gx2 }, 142 }; 143 SECItem x1; 144 145 PORT_Assert(params != NULL); 146 PORT_Assert(key != NULL); 147 148 arena = PORT_NewArena(NSS_SOFTOKEN_DEFAULT_CHUNKSIZE); 149 if (arena == NULL) 150 crv = CKR_HOST_MEMORY; 151 152 crv = sftk_MultipleAttribute2SecItem(arena, key, templateAttrs, 153 NUM_ELEM(templateAttrs)); 154 155 if (crv == CKR_OK && (signerID.data == NULL || signerID.len == 0)) 156 crv = CKR_TEMPLATE_INCOMPLETE; 157 158 /* generate x1, g^x1 and the proof of knowledge of x1 */ 159 if (crv == CKR_OK) { 160 x1.data = NULL; 161 crv = jpake_mapStatus(DSA_NewRandom(arena, &pqg.subPrime, &x1), 162 CKR_TEMPLATE_INCONSISTENT); 163 } 164 if (crv == CKR_OK) 165 crv = jpake_Sign(arena, &pqg, hashType, &signerID, &x1, ¶ms->gx1); 166 167 /* generate x2, g^x2 and the proof of knowledge of x2 */ 168 if (crv == CKR_OK) { 169 x2.data = NULL; 170 crv = jpake_mapStatus(DSA_NewRandom(arena, &pqg.subPrime, &x2), 171 CKR_TEMPLATE_INCONSISTENT); 172 } 173 if (crv == CKR_OK) 174 crv = jpake_Sign(arena, &pqg, hashType, &signerID, &x2, ¶ms->gx2); 175 176 /* Save the values needed for round 2 into CKA_VALUE */ 177 if (crv == CKR_OK) { 178 gx1.data = params->gx1.pGX; 179 gx1.len = params->gx1.ulGXLen; 180 gx2.data = params->gx2.pGX; 181 gx2.len = params->gx2.ulGXLen; 182 crv = jpake_MultipleSecItem2Attribute(key, generatedAttrs, 183 NUM_ELEM(generatedAttrs)); 184 } 185 186 PORT_FreeArena(arena, PR_TRUE); 187 return crv; 188 } 189 190 CK_RV 191 jpake_Round2(HASH_HashType hashType, CK_NSS_JPAKERound2Params *params, 192 SFTKObject *sourceKey, SFTKObject *key) 193 { 194 CK_RV crv; 195 PLArenaPool *arena; 196 PQGParams pqg; 197 SECItem signerID, x2, gx1, gx2; 198 SFTKItemTemplate sourceAttrs[] = { 199 { CKA_PRIME, &pqg.prime }, 200 { CKA_SUBPRIME, &pqg.subPrime }, 201 { CKA_BASE, &pqg.base }, 202 { CKA_NSS_JPAKE_SIGNERID, &signerID }, 203 { CKA_NSS_JPAKE_X2, &x2 }, 204 { CKA_NSS_JPAKE_GX1, &gx1 }, 205 { CKA_NSS_JPAKE_GX2, &gx2 }, 206 }; 207 SECItem x2s, gx3, gx4; 208 const SFTKItemTemplate copiedAndGeneratedAttrs[] = { 209 { CKA_NSS_JPAKE_SIGNERID, &signerID }, 210 { CKA_PRIME, &pqg.prime }, 211 { CKA_SUBPRIME, &pqg.subPrime }, 212 { CKA_NSS_JPAKE_X2, &x2 }, 213 { CKA_NSS_JPAKE_X2S, &x2s }, 214 { CKA_NSS_JPAKE_GX1, &gx1 }, 215 { CKA_NSS_JPAKE_GX2, &gx2 }, 216 { CKA_NSS_JPAKE_GX3, &gx3 }, 217 { CKA_NSS_JPAKE_GX4, &gx4 } 218 }; 219 SECItem peerID; 220 221 PORT_Assert(params != NULL); 222 PORT_Assert(sourceKey != NULL); 223 PORT_Assert(key != NULL); 224 225 arena = PORT_NewArena(NSS_SOFTOKEN_DEFAULT_CHUNKSIZE); 226 if (arena == NULL) 227 crv = CKR_HOST_MEMORY; 228 229 /* TODO: check CKK_NSS_JPAKE_ROUND1 */ 230 231 crv = sftk_MultipleAttribute2SecItem(arena, sourceKey, sourceAttrs, 232 NUM_ELEM(sourceAttrs)); 233 234 /* Get the peer's ID out of the template and sanity-check it. */ 235 if (crv == CKR_OK) 236 crv = sftk_Attribute2SecItem(arena, &peerID, key, 237 CKA_NSS_JPAKE_PEERID); 238 if (crv == CKR_OK && (peerID.data == NULL || peerID.len == 0)) 239 crv = CKR_TEMPLATE_INCOMPLETE; 240 if (crv == CKR_OK && SECITEM_CompareItem(&signerID, &peerID) == SECEqual) 241 crv = CKR_TEMPLATE_INCONSISTENT; 242 243 /* Verify zero-knowledge proofs for g^x3 and g^x4 */ 244 if (crv == CKR_OK) 245 crv = jpake_Verify(arena, &pqg, hashType, &signerID, 246 peerID.data, peerID.len, ¶ms->gx3); 247 if (crv == CKR_OK) 248 crv = jpake_Verify(arena, &pqg, hashType, &signerID, 249 peerID.data, peerID.len, ¶ms->gx4); 250 251 /* Calculate the base and x2s for A=base^x2s */ 252 if (crv == CKR_OK) { 253 SECItem s; 254 s.data = params->pSharedKey; 255 s.len = params->ulSharedKeyLen; 256 gx3.data = params->gx3.pGX; 257 gx3.len = params->gx3.ulGXLen; 258 gx4.data = params->gx4.pGX; 259 gx4.len = params->gx4.ulGXLen; 260 pqg.base.data = NULL; 261 x2s.data = NULL; 262 crv = jpake_mapStatus(JPAKE_Round2(arena, &pqg.prime, &pqg.subPrime, 263 &gx1, &gx3, &gx4, &pqg.base, 264 &x2, &s, &x2s), 265 CKR_MECHANISM_PARAM_INVALID); 266 } 267 268 /* Generate A=base^x2s and its zero-knowledge proof. */ 269 if (crv == CKR_OK) 270 crv = jpake_Sign(arena, &pqg, hashType, &signerID, &x2s, ¶ms->A); 271 272 /* Copy P and Q from the ROUND1 key to the ROUND2 key and save the values 273 needed for the final key material derivation into CKA_VALUE. */ 274 if (crv == CKR_OK) 275 crv = sftk_forceAttribute(key, CKA_PRIME, pqg.prime.data, 276 pqg.prime.len); 277 if (crv == CKR_OK) 278 crv = sftk_forceAttribute(key, CKA_SUBPRIME, pqg.subPrime.data, 279 pqg.subPrime.len); 280 if (crv == CKR_OK) { 281 crv = jpake_MultipleSecItem2Attribute(key, copiedAndGeneratedAttrs, 282 NUM_ELEM(copiedAndGeneratedAttrs)); 283 } 284 285 if (crv == CKR_OK) 286 crv = jpake_enforceKeyType(key, CKK_NSS_JPAKE_ROUND2); 287 288 PORT_FreeArena(arena, PR_TRUE); 289 return crv; 290 } 291 292 CK_RV 293 jpake_Final(HASH_HashType hashType, const CK_NSS_JPAKEFinalParams *param, 294 SFTKObject *sourceKey, SFTKObject *key) 295 { 296 PLArenaPool *arena; 297 SECItem K; 298 PQGParams pqg; 299 CK_RV crv; 300 SECItem peerID, signerID, x2s, x2, gx1, gx2, gx3, gx4; 301 SFTKItemTemplate sourceAttrs[] = { 302 { CKA_NSS_JPAKE_PEERID, &peerID }, 303 { CKA_NSS_JPAKE_SIGNERID, &signerID }, 304 { CKA_PRIME, &pqg.prime }, 305 { CKA_SUBPRIME, &pqg.subPrime }, 306 { CKA_NSS_JPAKE_X2, &x2 }, 307 { CKA_NSS_JPAKE_X2S, &x2s }, 308 { CKA_NSS_JPAKE_GX1, &gx1 }, 309 { CKA_NSS_JPAKE_GX2, &gx2 }, 310 { CKA_NSS_JPAKE_GX3, &gx3 }, 311 { CKA_NSS_JPAKE_GX4, &gx4 } 312 }; 313 314 PORT_Assert(param != NULL); 315 PORT_Assert(sourceKey != NULL); 316 PORT_Assert(key != NULL); 317 318 arena = PORT_NewArena(NSS_SOFTOKEN_DEFAULT_CHUNKSIZE); 319 if (arena == NULL) 320 crv = CKR_HOST_MEMORY; 321 322 /* TODO: verify key type CKK_NSS_JPAKE_ROUND2 */ 323 324 crv = sftk_MultipleAttribute2SecItem(arena, sourceKey, sourceAttrs, 325 NUM_ELEM(sourceAttrs)); 326 327 /* Calculate base for B=base^x4s */ 328 if (crv == CKR_OK) { 329 pqg.base.data = NULL; 330 crv = jpake_mapStatus(JPAKE_Round2(arena, &pqg.prime, &pqg.subPrime, 331 &gx1, &gx2, &gx3, &pqg.base, 332 NULL, NULL, NULL), 333 CKR_MECHANISM_PARAM_INVALID); 334 } 335 336 /* Verify zero-knowledge proof for B */ 337 if (crv == CKR_OK) 338 crv = jpake_Verify(arena, &pqg, hashType, &signerID, 339 peerID.data, peerID.len, ¶m->B); 340 if (crv == CKR_OK) { 341 SECItem B; 342 B.data = param->B.pGX; 343 B.len = param->B.ulGXLen; 344 K.data = NULL; 345 crv = jpake_mapStatus(JPAKE_Final(arena, &pqg.prime, &pqg.subPrime, 346 &x2, &gx4, &x2s, &B, &K), 347 CKR_MECHANISM_PARAM_INVALID); 348 } 349 350 /* Save key material into CKA_VALUE. */ 351 if (crv == CKR_OK) 352 crv = sftk_forceAttribute(key, CKA_VALUE, K.data, K.len); 353 354 if (crv == CKR_OK) 355 crv = jpake_enforceKeyType(key, CKK_GENERIC_SECRET); 356 357 PORT_FreeArena(arena, PR_TRUE); 358 return crv; 359 }