/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* TLS 1 . 3 Protocol
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2 . 0 . If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "keyhi.h"
#include "pk11func.h"
#include "secitem.h"
#include "ssl.h"
#include "sslt.h"
#include "sslerr.h"
#include "sslimpl.h"
/* This table contains the mapping between TLS hash identifiers and the
* PKCS#11 identifiers */
static const struct {
SSLHashType hash;
CK_MECHANISM_TYPE pkcs11Mech;
unsigned int hashSize;
} kTlsHkdfInfo[] = {
{ ssl_hash_none,
0 ,
0 },
{ ssl_hash_md5,
0 ,
0 },
{ ssl_hash_sha1,
0 ,
0 },
{ ssl_hash_sha224,
0 },
{ ssl_hash_sha256, CKM_SHA256,
32 },
{ ssl_hash_sha384, CKM_SHA384,
48 },
{ ssl_hash_sha512, CKM_SHA512,
64 }
};
SECStatus
tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2, SSLHashType baseHash,
PK11SymKey **prkp)
{
CK_HKDF_PARAMS params;
SECItem paramsi;
PK11SymKey *prk;
static const PRUint8 zeroKeyBuf[HASH_LENGTH_MAX];
SECItem zeroKeyItem = { siBuffer,
CONST_CAST (PRUint8, zeroKeyBuf), kTlsHkdfInfo[baseHas
h].hashSize };
PK11SlotInfo *slot = NULL;
PK11SymKey *newIkm2 = NULL;
PK11SymKey *newIkm1 = NULL;
SECStatus rv;
params.bExtract = CK_TRUE;
params.bExpand = CK_FALSE;
params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech;
params.pInfo = NULL;
params.ulInfoLen = 0 UL;
params.pSalt = NULL;
params.ulSaltLen = 0 UL;
params.hSaltKey = CK_INVALID_HANDLE;
if (!ikm1) {
/* PKCS #11 v3.0 has and explict NULL value, which equates to
* a sequence of zeros equal in length to the HMAC. */
params.ulSaltType = CKF_HKDF_SALT_NULL;
} else {
/* PKCS #11 v3.0 can take the salt as a key handle */
params.hSaltKey = PK11_GetSymKeyHandle(ikm1);
params.ulSaltType = CKF_HKDF_SALT_KEY;
/* if we have both keys, make sure they are in the same slot */
if (ikm2) {
rv = PK11_SymKeysToSameSlot(CKM_HKDF_DERIVE,
CKA_DERIVE, CKA_DERIVE,
ikm2, ikm1, &newIkm2, &newIkm1);
if (rv != SECSuccess) {
SECItem *salt;
/* couldn't move the keys, try extracting the salt */
rv = PK11_ExtractKeyValue(ikm1);
if (rv != SECSuccess)
return rv;
salt = PK11_GetKeyData(ikm1);
if (!salt)
return SECFailure;
PORT_Assert(salt->len > 0 );
/* Set up for Salt as Data instead of Salt as key */
params.pSalt = salt->data;
params.ulSaltLen = salt->len;
params.ulSaltType = CKF_HKDF_SALT_DATA;
}
/* use the new keys */
if (newIkm1) {
/* we've moved the key, get the handle for the new key */
params.hSaltKey = PK11_GetSymKeyHandle(newIkm1);
/* we don't use ikm1 after this, so don't bother setting it */
}
if (newIkm2) {
/* new ikm2 key, use the new key */
ikm2 = newIkm2;
}
}
}
paramsi.data = (unsigned char *)¶ms;
paramsi.len = sizeof (params);
PORT_Assert(kTlsHkdfInfo[baseHash].pkcs11Mech);
PORT_Assert(kTlsHkdfInfo[baseHash].hashSize);
PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash);
/* A zero ikm2 is a key of hash-length 0s. */
if (!ikm2) {
/* if we have ikm1, put the zero key in the same slot */
slot = ikm1 ? PK11_GetSlotFromKey(ikm1) : PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL);
if (!slot) {
return SECFailure;
}
newIkm2 = PK11_ImportDataKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap,
CKA_DERIVE, &zeroKeyItem, NULL);
if (!newIkm2) {
return SECFailure;
}
ikm2 = newIkm2;
}
PORT_Assert(ikm2);
PRINT_BUF(50 , (NULL, "HKDF Extract: IKM1/Salt" , params.pSalt, params.ulSaltLen));
PRINT_KEY(50 , (NULL, "HKDF Extract: IKM2" , ikm2));
prk = PK11_Derive(ikm2, CKM_HKDF_DERIVE, ¶msi, CKM_HKDF_DERIVE,
CKA_DERIVE, 0 );
PK11_FreeSymKey(newIkm2);
PK11_FreeSymKey(newIkm1);
if (slot)
PK11_FreeSlot(slot);
if (!prk) {
return SECFailure;
}
PRINT_KEY(50 , (NULL, "HKDF Extract" , prk));
*prkp = prk;
return SECSuccess;
}
SECStatus
tls13_HkdfExpandLabelGeneral(CK_MECHANISM_TYPE deriveMech, PK11SymKey *prk,
SSLHashType baseHash,
const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
const char *label, unsigned int labelLen,
CK_MECHANISM_TYPE algorithm, unsigned int keySize,
SSLProtocolVariant variant, PK11SymKey **keyp)
{
CK_HKDF_PARAMS params;
SECItem paramsi = { siBuffer, NULL, 0 };
/* Size of info array needs to be big enough to hold the maximum Prefix,
* Label , plus HandshakeHash . If it ' s ever to small , the code will abort .
*/
PRUint8 info[256 ];
sslBuffer infoBuf = SSL_BUFFER(info);
PK11SymKey *derived;
SECStatus rv;
const char *kLabelPrefixTls = "tls13 " ;
const char *kLabelPrefixDtls = "dtls13" ;
const unsigned int kLabelPrefixLen =
(variant == ssl_variant_stream) ? strlen(kLabelPrefixTls) : strlen(kLabelPrefixDtls);
const char *kLabelPrefix =
(variant == ssl_variant_stream) ? kLabelPrefixTls : kLabelPrefixDtls;
PORT_Assert(prk);
PORT_Assert(keyp);
if ((handshakeHashLen > 255 ) ||
(handshakeHash == NULL && handshakeHashLen > 0 ) ||
(labelLen + kLabelPrefixLen > 255 )) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/*
* [ draft - ietf - tls - tls13 - 11 ] Section 7 . 1 :
*
* HKDF - Expand - Label ( Secret , Label , HashValue , Length ) =
* HKDF - Expand ( Secret , HkdfLabel , Length )
*
* Where HkdfLabel is specified as :
*
* struct HkdfLabel {
* uint16 length ;
* opaque label < 9 . . 255 > ;
* opaque hash_value < 0 . . 255 > ;
* } ;
*
* Where :
* - HkdfLabel . length is Length
* - HkdfLabel . hash_value is HashValue .
* - HkdfLabel . label is " TLS 1 . 3 , " + Label
*
*/
rv = sslBuffer_AppendNumber(&infoBuf, keySize, 2 );
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(&infoBuf, labelLen + kLabelPrefixLen, 1 );
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_Append(&infoBuf, kLabelPrefix, kLabelPrefixLen);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_Append(&infoBuf, label, labelLen);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendVariable(&infoBuf, handshakeHash, handshakeHashLen, 1 );
if (rv != SECSuccess) {
return SECFailure;
}
params.bExtract = CK_FALSE;
params.bExpand = CK_TRUE;
params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech;
params.pInfo = SSL_BUFFER_BASE(&infoBuf);
params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf);
paramsi.data = (unsigned char *)¶ms;
paramsi.len = sizeof (params);
derived = PK11_DeriveWithFlags(prk, deriveMech,
¶msi, algorithm,
CKA_DERIVE, keySize,
CKF_SIGN | CKF_VERIFY);
if (!derived) {
return SECFailure;
}
*keyp = derived;
#ifdef TRACE
if (ssl_trace >= 50 ) {
/* Make sure the label is null terminated. */
char labelStr[100 ];
PORT_Memcpy(labelStr, label, labelLen);
labelStr[labelLen] = 0 ;
SSL_TRC(50 , ("HKDF Expand: label='tls13 %s',requested length=%d" ,
labelStr, keySize));
}
PRINT_KEY(50 , (NULL, "PRK" , prk));
PRINT_BUF(50 , (NULL, "Hash" , handshakeHash, handshakeHashLen));
PRINT_BUF(50 , (NULL, "Info" , SSL_BUFFER_BASE(&infoBuf),
SSL_BUFFER_LEN(&infoBuf)));
PRINT_KEY(50 , (NULL, "Derived key" , derived));
#endif
return SECSuccess;
}
SECStatus
tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
const char *label, unsigned int labelLen,
CK_MECHANISM_TYPE algorithm, unsigned int keySize,
SSLProtocolVariant variant, PK11SymKey **keyp)
{
return tls13_HkdfExpandLabelGeneral(CKM_HKDF_DERIVE, prk, baseHash,
handshakeHash, handshakeHashLen,
label, labelLen, algorithm, keySize,
variant, keyp);
}
SECStatus
tls13_HkdfExpandLabelRaw(PK11SymKey *prk, SSLHashType baseHash,
const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
const char *label, unsigned int labelLen,
SSLProtocolVariant variant, unsigned char *output,
unsigned int outputLen)
{
PK11SymKey *derived = NULL;
SECItem *rawkey;
SECStatus rv;
/* the result is not really a key, it's a data object */
rv = tls13_HkdfExpandLabelGeneral(CKM_HKDF_DATA, prk, baseHash,
handshakeHash, handshakeHashLen,
label, labelLen, CKM_HKDF_DERIVE, outputLen,
variant, &derived);
if (rv != SECSuccess || !derived) {
goto abort;
}
rv = PK11_ExtractKeyValue(derived);
if (rv != SECSuccess) {
goto abort;
}
rawkey = PK11_GetKeyData(derived);
if (!rawkey) {
goto abort;
}
PORT_Assert(rawkey->len == outputLen);
memcpy(output, rawkey->data, outputLen);
PK11_FreeSymKey(derived);
return SECSuccess;
abort:
if (derived) {
PK11_FreeSymKey(derived);
}
PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
return SECFailure;
}
Messung V0.5 in Prozent C=94 H=95 G=94
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland