sslprimitive.c (17030B)
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * SSL Primitives: Public HKDF and AEAD Functions 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 8 9 #include "blapit.h" 10 #include "keyhi.h" 11 #include "pk11pub.h" 12 #include "sechash.h" 13 #include "ssl.h" 14 #include "sslexp.h" 15 #include "sslerr.h" 16 #include "sslproto.h" 17 18 #include "sslimpl.h" 19 #include "tls13con.h" 20 #include "tls13hkdf.h" 21 22 struct SSLAeadContextStr { 23 /* sigh, the API creates a single context, but then uses either encrypt 24 * and decrypt on that context. We should take an encrypt/decrypt 25 * variable here, but for now create two contexts. */ 26 PK11Context *encryptContext; 27 PK11Context *decryptContext; 28 int tagLen; 29 int ivLen; 30 unsigned char iv[MAX_IV_LENGTH]; 31 }; 32 33 SECStatus 34 SSLExp_MakeVariantAead(PRUint16 version, PRUint16 cipherSuite, SSLProtocolVariant variant, 35 PK11SymKey *secret, const char *labelPrefix, 36 unsigned int labelPrefixLen, SSLAeadContext **ctx) 37 { 38 SSLAeadContext *out = NULL; 39 char label[255]; // Maximum length label. 40 static const char *const keySuffix = "key"; 41 static const char *const ivSuffix = "iv"; 42 CK_MECHANISM_TYPE mech; 43 SECItem nullParams = { siBuffer, NULL, 0 }; 44 PK11SymKey *key = NULL; 45 46 PORT_Assert(strlen(keySuffix) >= strlen(ivSuffix)); 47 if (secret == NULL || ctx == NULL || 48 (labelPrefix == NULL && labelPrefixLen > 0) || 49 labelPrefixLen + strlen(keySuffix) > sizeof(label)) { 50 PORT_SetError(SEC_ERROR_INVALID_ARGS); 51 goto loser; 52 } 53 54 SSLHashType hash; 55 const ssl3BulkCipherDef *cipher; 56 SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite, 57 &hash, &cipher); 58 if (rv != SECSuccess) { 59 goto loser; /* Code already set. */ 60 } 61 62 out = PORT_ZNew(SSLAeadContext); 63 if (out == NULL) { 64 goto loser; 65 } 66 mech = ssl3_Alg2Mech(cipher->calg); 67 out->ivLen = cipher->iv_size + cipher->explicit_nonce_size; 68 out->tagLen = cipher->tag_size; 69 70 if (labelPrefixLen > 0) { 71 memcpy(label, labelPrefix, labelPrefixLen); 72 } 73 memcpy(label + labelPrefixLen, ivSuffix, strlen(ivSuffix)); 74 unsigned int labelLen = labelPrefixLen + strlen(ivSuffix); 75 unsigned int ivLen = cipher->iv_size + cipher->explicit_nonce_size; 76 rv = tls13_HkdfExpandLabelRaw(secret, hash, 77 NULL, 0, // Handshake hash. 78 label, labelLen, variant, 79 out->iv, ivLen); 80 if (rv != SECSuccess) { 81 goto loser; 82 } 83 84 memcpy(label + labelPrefixLen, keySuffix, strlen(keySuffix)); 85 labelLen = labelPrefixLen + strlen(keySuffix); 86 rv = tls13_HkdfExpandLabel(secret, hash, 87 NULL, 0, // Handshake hash. 88 label, labelLen, mech, cipher->key_size, 89 variant, &key); 90 if (rv != SECSuccess) { 91 goto loser; 92 } 93 94 /* We really need to change the API to Create a context for each 95 * encrypt and decrypt rather than a single call that does both. it's 96 * almost certain that the underlying application tries to use the same 97 * context for both. */ 98 out->encryptContext = PK11_CreateContextBySymKey(mech, 99 CKA_NSS_MESSAGE | CKA_ENCRYPT, 100 key, &nullParams); 101 if (out->encryptContext == NULL) { 102 goto loser; 103 } 104 105 out->decryptContext = PK11_CreateContextBySymKey(mech, 106 CKA_NSS_MESSAGE | CKA_DECRYPT, 107 key, &nullParams); 108 if (out->decryptContext == NULL) { 109 goto loser; 110 } 111 112 PK11_FreeSymKey(key); 113 *ctx = out; 114 return SECSuccess; 115 116 loser: 117 PK11_FreeSymKey(key); 118 SSLExp_DestroyAead(out); 119 return SECFailure; 120 } 121 122 SECStatus 123 SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret, 124 const char *labelPrefix, unsigned int labelPrefixLen, SSLAeadContext **ctx) 125 { 126 return SSLExp_MakeVariantAead(version, cipherSuite, ssl_variant_stream, secret, 127 labelPrefix, labelPrefixLen, ctx); 128 } 129 130 SECStatus 131 SSLExp_DestroyAead(SSLAeadContext *ctx) 132 { 133 if (!ctx) { 134 return SECSuccess; 135 } 136 if (ctx->encryptContext) { 137 PK11_DestroyContext(ctx->encryptContext, PR_TRUE); 138 } 139 if (ctx->decryptContext) { 140 PK11_DestroyContext(ctx->decryptContext, PR_TRUE); 141 } 142 143 PORT_ZFree(ctx, sizeof(*ctx)); 144 return SECSuccess; 145 } 146 147 /* Bug 1529440 exists to refactor this and the other AEAD uses. */ 148 static SECStatus 149 ssl_AeadInner(const SSLAeadContext *ctx, PK11Context *context, 150 PRBool decrypt, PRUint64 counter, 151 const PRUint8 *aad, unsigned int aadLen, 152 const PRUint8 *in, unsigned int inLen, 153 PRUint8 *out, unsigned int *outLen, unsigned int maxOut) 154 { 155 if (ctx == NULL || (aad == NULL && aadLen > 0) || in == NULL || 156 out == NULL || outLen == NULL) { 157 PORT_SetError(SEC_ERROR_INVALID_ARGS); 158 return SECFailure; 159 } 160 161 // Setup the nonce. 162 PRUint8 nonce[sizeof(counter)] = { 0 }; 163 sslBuffer nonceBuf = SSL_BUFFER_FIXED(nonce, sizeof(counter)); 164 SECStatus rv = sslBuffer_AppendNumber(&nonceBuf, counter, sizeof(counter)); 165 if (rv != SECSuccess) { 166 PORT_Assert(0); 167 return SECFailure; 168 } 169 /* at least on encrypt, we should not be using CKG_NO_GENERATE, but 170 * the current experimental API has the application tracking the counter 171 * rather than token. We should look at the QUIC code and see if the 172 * counter can be moved internally where it belongs. That would 173 * also get rid of the formatting code above and have the API 174 * call tls13_AEAD directly in SSLExp_Aead* */ 175 return tls13_AEAD(context, decrypt, CKG_NO_GENERATE, 0, ctx->iv, NULL, 176 ctx->ivLen, nonce, sizeof(counter), aad, aadLen, 177 out, outLen, maxOut, ctx->tagLen, in, inLen); 178 } 179 180 SECStatus 181 SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter, 182 const PRUint8 *aad, unsigned int aadLen, 183 const PRUint8 *plaintext, unsigned int plaintextLen, 184 PRUint8 *out, unsigned int *outLen, unsigned int maxOut) 185 { 186 // false == encrypt 187 return ssl_AeadInner(ctx, ctx->encryptContext, PR_FALSE, counter, 188 aad, aadLen, plaintext, plaintextLen, 189 out, outLen, maxOut); 190 } 191 192 SECStatus 193 SSLExp_AeadDecrypt(const SSLAeadContext *ctx, PRUint64 counter, 194 const PRUint8 *aad, unsigned int aadLen, 195 const PRUint8 *ciphertext, unsigned int ciphertextLen, 196 PRUint8 *out, unsigned int *outLen, unsigned int maxOut) 197 { 198 // true == decrypt 199 return ssl_AeadInner(ctx, ctx->decryptContext, PR_TRUE, counter, 200 aad, aadLen, ciphertext, ciphertextLen, 201 out, outLen, maxOut); 202 } 203 204 SECStatus 205 SSLExp_HkdfExtract(PRUint16 version, PRUint16 cipherSuite, 206 PK11SymKey *salt, PK11SymKey *ikm, PK11SymKey **keyp) 207 { 208 if (keyp == NULL) { 209 PORT_SetError(SEC_ERROR_INVALID_ARGS); 210 return SECFailure; 211 } 212 213 SSLHashType hash; 214 SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite, 215 &hash, NULL); 216 if (rv != SECSuccess) { 217 return SECFailure; /* Code already set. */ 218 } 219 return tls13_HkdfExtract(salt, ikm, hash, keyp); 220 } 221 222 SECStatus 223 SSLExp_HkdfExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk, 224 const PRUint8 *hsHash, unsigned int hsHashLen, 225 const char *label, unsigned int labelLen, PK11SymKey **keyp) 226 { 227 return SSLExp_HkdfVariantExpandLabel(version, cipherSuite, prk, hsHash, hsHashLen, 228 label, labelLen, ssl_variant_stream, keyp); 229 } 230 231 SECStatus 232 SSLExp_HkdfVariantExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk, 233 const PRUint8 *hsHash, unsigned int hsHashLen, 234 const char *label, unsigned int labelLen, 235 SSLProtocolVariant variant, PK11SymKey **keyp) 236 { 237 if (prk == NULL || keyp == NULL || 238 label == NULL || labelLen == 0) { 239 PORT_SetError(SEC_ERROR_INVALID_ARGS); 240 return SECFailure; 241 } 242 243 SSLHashType hash; 244 SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite, 245 &hash, NULL); 246 if (rv != SECSuccess) { 247 return SECFailure; /* Code already set. */ 248 } 249 return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen, 250 CKM_HKDF_DERIVE, 251 tls13_GetHashSizeForHash(hash), variant, keyp); 252 } 253 254 SECStatus 255 SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk, 256 const PRUint8 *hsHash, unsigned int hsHashLen, 257 const char *label, unsigned int labelLen, 258 CK_MECHANISM_TYPE mech, unsigned int keySize, 259 PK11SymKey **keyp) 260 { 261 return SSLExp_HkdfVariantExpandLabelWithMech(version, cipherSuite, prk, hsHash, hsHashLen, 262 label, labelLen, mech, keySize, 263 ssl_variant_stream, keyp); 264 } 265 266 SECStatus 267 SSLExp_HkdfVariantExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk, 268 const PRUint8 *hsHash, unsigned int hsHashLen, 269 const char *label, unsigned int labelLen, 270 CK_MECHANISM_TYPE mech, unsigned int keySize, 271 SSLProtocolVariant variant, PK11SymKey **keyp) 272 { 273 if (prk == NULL || keyp == NULL || 274 label == NULL || labelLen == 0 || 275 mech == CKM_INVALID_MECHANISM || keySize == 0) { 276 PORT_SetError(SEC_ERROR_INVALID_ARGS); 277 return SECFailure; 278 } 279 280 SSLHashType hash; 281 SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite, 282 &hash, NULL); 283 if (rv != SECSuccess) { 284 return SECFailure; /* Code already set. */ 285 } 286 return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen, 287 mech, keySize, variant, keyp); 288 } 289 290 SECStatus 291 ssl_CreateMaskingContextInner(PRUint16 version, PRUint16 cipherSuite, 292 SSLProtocolVariant variant, 293 PK11SymKey *secret, 294 const char *label, 295 unsigned int labelLen, 296 SSLMaskingContext **ctx) 297 { 298 if (!secret || !ctx || (!label && labelLen)) { 299 PORT_SetError(SEC_ERROR_INVALID_ARGS); 300 return SECFailure; 301 } 302 303 SSLMaskingContext *out = PORT_ZNew(SSLMaskingContext); 304 if (out == NULL) { 305 goto loser; 306 } 307 308 SSLHashType hash; 309 const ssl3BulkCipherDef *cipher; 310 SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite, 311 &hash, &cipher); 312 if (rv != SECSuccess) { 313 PORT_SetError(SEC_ERROR_INVALID_ARGS); 314 goto loser; /* Code already set. */ 315 } 316 317 out->mech = tls13_SequenceNumberEncryptionMechanism(cipher->calg); 318 if (out->mech == CKM_INVALID_MECHANISM) { 319 PORT_SetError(SEC_ERROR_INVALID_ARGS); 320 goto loser; 321 } 322 323 // Derive the masking key 324 rv = tls13_HkdfExpandLabel(secret, hash, 325 NULL, 0, // Handshake hash. 326 label, labelLen, 327 out->mech, 328 cipher->key_size, variant, 329 &out->secret); 330 if (rv != SECSuccess) { 331 goto loser; 332 } 333 334 out->version = version; 335 out->cipherSuite = cipherSuite; 336 337 *ctx = out; 338 return SECSuccess; 339 loser: 340 SSLExp_DestroyMaskingContext(out); 341 return SECFailure; 342 } 343 344 SECStatus 345 ssl_CreateMaskInner(SSLMaskingContext *ctx, const PRUint8 *sample, 346 unsigned int sampleLen, PRUint8 *outMask, 347 unsigned int maskLen) 348 { 349 if (!ctx || !sample || !sampleLen || !outMask || !maskLen) { 350 PORT_SetError(SEC_ERROR_INVALID_ARGS); 351 return SECFailure; 352 } 353 354 if (ctx->secret == NULL) { 355 PORT_SetError(SEC_ERROR_NO_KEY); 356 return SECFailure; 357 } 358 359 SECStatus rv = SECFailure; 360 unsigned int outMaskLen = 0; 361 int paramLen = 0; 362 363 /* Internal output len/buf, for use if the caller allocated and requested 364 * less than one block of output. |oneBlock| should have size equal to the 365 * largest block size supported below. */ 366 PRUint8 oneBlock[AES_BLOCK_SIZE]; 367 PRUint8 *outMask_ = outMask; 368 unsigned int maskLen_ = maskLen; 369 370 switch (ctx->mech) { 371 case CKM_AES_ECB: 372 if (sampleLen < AES_BLOCK_SIZE) { 373 PORT_SetError(SEC_ERROR_INVALID_ARGS); 374 return SECFailure; 375 } 376 if (maskLen_ < AES_BLOCK_SIZE) { 377 outMask_ = oneBlock; 378 maskLen_ = sizeof(oneBlock); 379 } 380 rv = PK11_Encrypt(ctx->secret, 381 ctx->mech, 382 NULL, 383 outMask_, &outMaskLen, maskLen_, 384 sample, AES_BLOCK_SIZE); 385 if (rv == SECSuccess && 386 maskLen < AES_BLOCK_SIZE) { 387 memcpy(outMask, outMask_, maskLen); 388 } 389 break; 390 case CKM_NSS_CHACHA20_CTR: 391 paramLen = 16; 392 /* fall through */ 393 case CKM_CHACHA20: 394 paramLen = (paramLen) ? paramLen : sizeof(CK_CHACHA20_PARAMS); 395 if (sampleLen < paramLen) { 396 PORT_SetError(SEC_ERROR_INVALID_ARGS); 397 return SECFailure; 398 } 399 400 SECItem param; 401 param.type = siBuffer; 402 param.len = paramLen; 403 param.data = (PRUint8 *)sample; // const-cast :( 404 unsigned char zeros[128] = { 0 }; 405 406 if (maskLen > sizeof(zeros)) { 407 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 408 return SECFailure; 409 } 410 411 rv = PK11_Encrypt(ctx->secret, 412 ctx->mech, 413 ¶m, 414 outMask, &outMaskLen, 415 maskLen, 416 zeros, maskLen); 417 break; 418 default: 419 PORT_SetError(SEC_ERROR_INVALID_ARGS); 420 return SECFailure; 421 } 422 423 if (rv != SECSuccess) { 424 PORT_SetError(SEC_ERROR_PKCS11_FUNCTION_FAILED); 425 return SECFailure; 426 } 427 428 // Ensure we produced at least as much material as requested. 429 if (outMaskLen < maskLen) { 430 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 431 return SECFailure; 432 } 433 434 return SECSuccess; 435 } 436 437 SECStatus 438 ssl_DestroyMaskingContextInner(SSLMaskingContext *ctx) 439 { 440 if (!ctx) { 441 return SECSuccess; 442 } 443 444 PK11_FreeSymKey(ctx->secret); 445 PORT_ZFree(ctx, sizeof(*ctx)); 446 return SECSuccess; 447 } 448 449 SECStatus 450 SSLExp_CreateMask(SSLMaskingContext *ctx, const PRUint8 *sample, 451 unsigned int sampleLen, PRUint8 *outMask, 452 unsigned int maskLen) 453 { 454 return ssl_CreateMaskInner(ctx, sample, sampleLen, outMask, maskLen); 455 } 456 457 SECStatus 458 SSLExp_CreateMaskingContext(PRUint16 version, PRUint16 cipherSuite, 459 PK11SymKey *secret, 460 const char *label, 461 unsigned int labelLen, 462 SSLMaskingContext **ctx) 463 { 464 return ssl_CreateMaskingContextInner(version, cipherSuite, ssl_variant_stream, secret, 465 label, labelLen, ctx); 466 } 467 468 SECStatus 469 SSLExp_CreateVariantMaskingContext(PRUint16 version, PRUint16 cipherSuite, 470 SSLProtocolVariant variant, 471 PK11SymKey *secret, 472 const char *label, 473 unsigned int labelLen, 474 SSLMaskingContext **ctx) 475 { 476 return ssl_CreateMaskingContextInner(version, cipherSuite, variant, secret, 477 label, labelLen, ctx); 478 } 479 480 SECStatus 481 SSLExp_DestroyMaskingContext(SSLMaskingContext *ctx) 482 { 483 return ssl_DestroyMaskingContextInner(ctx); 484 }