MastersThesis/PQ_TIIGER_TLS/lib/tls_keys_calc.cpp
2024-04-19 14:16:07 +02:00

444 lines
14 KiB
C++

//
// TLS1.3 crypto support functions (hashing, KDFs etc)
//
#include "tls_keys_calc.h"
#include "tls_logger.h"
#include "tls_x509.h"
// Initialise transcript hash
void initTranscriptHash(TLS_session *session)
{
int hashtype=SAL_hashType(session->cipher_suite);
SAL_hashInit(hashtype,&session->tlshash);
}
// Add octad to transcript hash
void runningHash(TLS_session *session,octad *O)
{
SAL_hashProcessArray(&session->tlshash,O->val,O->len);
}
// Add IO buffer to transcript hash
void runningHashIO(TLS_session *session)
{
SAL_hashProcessArray(&session->tlshash,session->IBUFF.val,session->ptr);
}
// Shift octad left - rewind IO buffer to start
void rewindIO(TLS_session *session)
{
OCT_shift_left(&session->IBUFF,session->ptr);
session->ptr=0;
}
void runningHashIOrewind(TLS_session *session)
{
runningHashIO(session);
rewindIO(session);
}
// Output transcript hash
void transcriptHash(TLS_session *session,octad *O)
{
O->len=SAL_hashOutput(&session->tlshash,O->val);
}
// special case handling for first clientHello after retry request
void runningSyntheticHash(TLS_session *session,octad *O,octad *E)
{
int htype=session->tlshash.htype;
unihash rhash;
char hh[TLS_MAX_HASH];
octad HH={0,sizeof(hh),hh};
SAL_hashInit(htype,&rhash);
// RFC 8446 - "special synthetic message"
SAL_hashProcessArray(&rhash,O->val,O->len);
SAL_hashProcessArray(&rhash,E->val,E->len);
HH.len=SAL_hashOutput(&rhash,HH.val);
char t[4];
t[0]=MESSAGE_HASH;
t[1]=t[2]=0;
t[3]=SAL_hashLen(htype);
SAL_hashProcessArray(&session->tlshash,t,4);
runningHash(session,&HH);
}
// Initialise crypto context (Key,IV, Record number)
void initCryptoContext(crypto *C)
{
C->active=false;
C->K.len = 0;
C->K.max = TLS_MAX_KEY;
C->K.val = C->k;
C->IV.len = 0;
C->IV.max = 12;
C->IV.val = C->iv;
C->suite=TLS_AES_128_GCM_SHA256; // default
C->record=0;
C->taglen=16; // default
}
// Fill a crypto context with new key/IV
void updateCryptoContext(crypto *C,octad *K,octad *IV)
{
C->active=true;
OCT_copy(&(C->K),K);
OCT_copy(&(C->IV),IV);
C->record=0;
}
// increment record, and update IV
void incrementCryptoContext(crypto *C)
{
unsigned char b[4];
b[3] = (unsigned char)(C->record);
b[2] = (unsigned char)(C->record >> 8);
b[1] = (unsigned char)(C->record >> 16);
b[0] = (unsigned char)(C->record >> 24);
for (int i=0;i<4;i++)
C->IV.val[8+i]^=b[i]; // revert to original IV
C->record++;
b[3] = (unsigned char)(C->record);
b[2] = (unsigned char)(C->record >> 8);
b[1] = (unsigned char)(C->record >> 16);
b[0] = (unsigned char)(C->record >> 24);
for (int i=0;i<4;i++)
C->IV.val[8+i]^=b[i]; // advance to new IV
}
// create expanded HKDF label LB from label and context
static void hkdfLabel(octad *LB,int length,octad *Label,octad *CTX)
{
OCT_append_int(LB,length,2); // 2
OCT_append_byte(LB,(char)(6+Label->len),1); // 1
OCT_append_string(LB,(char *)"tls13 "); // 6
OCT_append_octad(LB,Label); // Label->len
if (CTX!=NULL)
{
OCT_append_byte(LB, (char)(CTX->len), 1); // 1
OCT_append_octad(LB,CTX); // CTX->len
} else {
OCT_append_byte(LB,0,1); // 1
}
}
// HKDF extension for TLS1.3
static void hkdfExpandLabel(int htype,octad *OKM,int olen,octad *PRK,octad *Label,octad *CTX)
{
char hl[TLS_MAX_HASH+24];
octad HL={0,sizeof(hl),hl};
hkdfLabel(&HL,olen,Label,CTX);
SAL_hkdfExpand(htype,olen,OKM,PRK,&HL);
}
// create verification data
void deriveVeriferData(int htype,octad *CF,octad *CHTS,octad *H)
{
char fk[TLS_MAX_HASH];
octad FK = {0,sizeof(fk),fk};
char info[10];
octad INFO = {0,sizeof(info),info};
int hlen=SAL_hashLen(htype);
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"finished");
hkdfExpandLabel(htype,&FK,hlen,CHTS,&INFO,NULL);
SAL_hmac(htype,CF,&FK,H);
}
// check verification data
bool checkVeriferData(int htype,octad *SF,octad *SHTS,octad *H)
{
char vd[TLS_MAX_HASH];
octad VD = {0,sizeof(vd),vd};
deriveVeriferData(htype,&VD,SHTS,H);
return OCT_compare(SF,&VD);
}
// update Traffic secret and associated traffic key and IV
void deriveUpdatedKeys(crypto *context,octad *TS)
{
int htype,sha,key;
char info[16];
octad INFO = {0,sizeof(info),info};
char nts[TLS_MAX_HASH];
octad NTS={0,sizeof(nts),nts};
// find cipher suite
htype=SAL_hashType(context->suite);
sha=SAL_hashLen(htype);
key=SAL_aeadKeylen(context->suite); // depends on key length
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"traffic upd");
hkdfExpandLabel(htype,&NTS,sha,TS,&INFO,NULL);
OCT_copy(TS,&NTS);
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"key");
hkdfExpandLabel(htype,&(context->K),key,TS,&INFO,NULL);
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"iv");
hkdfExpandLabel(htype,&(context->IV),12,TS,&INFO,NULL);
// reset record number
context->record=0;
context->active=true;
}
// Create a crypto context from an input raw Secret and an agreed cipher_suite
void createCryptoContext(int cipher_suite,octad *TS,crypto *context)
{
int key,htype=SAL_hashType(cipher_suite);
key=SAL_aeadKeylen(cipher_suite);
char info[8];
octad INFO = {0,sizeof(info),info};
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"key");
hkdfExpandLabel(htype,&(context->K),key,TS,&INFO,NULL);
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"iv");
hkdfExpandLabel(htype,&(context->IV),12,TS,&INFO,NULL);
context->active=true;
context->suite=cipher_suite;
context->record=0;
context->taglen=SAL_aeadTaglen(cipher_suite);
}
void createSendCryptoContext(TLS_session *session,octad *TS)
{
createCryptoContext(session->cipher_suite,TS,&session->K_send);
}
void createRecvCryptoContext(TLS_session *session,octad *TS)
{
createCryptoContext(session->cipher_suite,TS,&session->K_recv);
}
// recover Pre-Shared-Key from Resumption Master Secret
void recoverPSK(TLS_session *session)
{
char info[16];
octad INFO = {0,sizeof(info),info};
int htype=SAL_hashType(session->cipher_suite);
int hlen=SAL_hashLen(htype);
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"resumption");
hkdfExpandLabel(htype,&session->T.PSK,hlen,&session->RMS, &INFO, &session->T.NONCE);
}
// Key Schedule code
// Get Early Secret ES and optional Binder Key (either External or Resumption)
void deriveEarlySecrets(int htype,octad *PSK,octad *ES,octad *BKE,octad *BKR)
{
char emh[TLS_MAX_HASH];
octad EMH = {0,sizeof(emh),emh};
char zk[TLS_MAX_HASH];
octad ZK = {0,sizeof(zk),zk};
char info[16];
octad INFO = {0,sizeof(info),info};
int hlen=SAL_hashLen(htype);
OCT_append_byte(&ZK,0,hlen); // Zero key
if (PSK==NULL)
OCT_copy(&EMH,&ZK); // if no PSK available use ZK
else
OCT_copy(&EMH,PSK);
SAL_hkdfExtract(htype,ES,&ZK,&EMH); // hash function, ES is output, ZK is salt and EMH is IKM
SAL_hashNull(htype,&EMH); // EMH = hash of ""
if (BKE!=NULL)
{ // External Binder Key
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"ext binder");
hkdfExpandLabel(htype,BKE,hlen,ES,&INFO,&EMH);
}
if (BKR!=NULL)
{ // Resumption Binder Key
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"res binder");
hkdfExpandLabel(htype,BKR,hlen,ES,&INFO,&EMH);
}
}
// Get Later Secrets (Client Early Traffic Secret CETS and Early Exporter Master Secret EEMS) - requires partial transcript hash H
void deriveLaterSecrets(int htype,octad *ES,octad *H,octad *CETS,octad *EEMS)
{
char info[16];
octad INFO = {0,sizeof(info),info};
int hlen=SAL_hashLen(htype);
if (CETS!=NULL)
{
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"c e traffic");
hkdfExpandLabel(htype,CETS,hlen,ES,&INFO,H);
}
if (EEMS!=NULL)
{
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"e exp master");
hkdfExpandLabel(htype,EEMS,hlen,ES,&INFO,H);
}
}
// get Client and Server Handshake secrets for encrypting rest of handshake, from Shared secret SS and early secret ES
void deriveHandshakeSecrets(TLS_session *session,octad *SS,octad *ES,octad *H)
{
char ds[TLS_MAX_HASH];
octad DS = {0,sizeof(ds),ds}; // Derived Secret
char emh[TLS_MAX_HASH];
octad EMH = {0,sizeof(emh),emh}; // Empty Hash
char info[16];
octad INFO = {0,sizeof(info),info};
int htype=SAL_hashType(session->cipher_suite);
int hlen=SAL_hashLen(htype);
SAL_hashNull(htype,&EMH); // hash of ""
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"derived");
hkdfExpandLabel(htype,&DS,hlen,ES,&INFO,&EMH);
SAL_hkdfExtract(htype,&session->HS,&DS,SS);
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"c hs traffic");
hkdfExpandLabel(htype,&session->CTS,hlen,&session->HS,&INFO,H);
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"s hs traffic");
hkdfExpandLabel(htype,&session->STS,hlen,&session->HS,&INFO,H);
}
// Extract Client and Server Application Traffic secrets from Transcript Hashes, Handshake secret
// SFH - Server Finished Hash
// CFH - Client Finished Hash
void deriveApplicationSecrets(TLS_session *session,octad *SFH,octad *CFH,octad *EMS)
{
char ds[TLS_MAX_HASH];
octad DS = {0,sizeof(ds),ds};
char ms[TLS_MAX_HASH];
octad MS = {0,sizeof(ms),ms};
char emh[TLS_MAX_HASH];
octad EMH = {0,sizeof(emh),emh};
char zk[TLS_MAX_HASH]; // Zero Key
octad ZK = {0,sizeof(zk),zk};
char info[16];
octad INFO = {0,sizeof(info),info};
int htype=SAL_hashType(session->cipher_suite);
int hlen=SAL_hashLen(htype);
OCT_append_byte(&ZK,0,hlen); // 00..00
SAL_hashNull(htype,&EMH); // hash("")
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"derived");
hkdfExpandLabel(htype,&DS,hlen,&session->HS,&INFO,&EMH); // Use handshake secret from above
SAL_hkdfExtract(htype,&MS,&DS,&ZK);
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"c ap traffic");
hkdfExpandLabel(htype,&session->CTS,hlen,&MS,&INFO,SFH);
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"s ap traffic");
hkdfExpandLabel(htype,&session->STS,hlen,&MS,&INFO,SFH);
if (EMS!=NULL)
{
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"exp master");
hkdfExpandLabel(htype,EMS,hlen,&MS,&INFO,SFH);
}
OCT_kill(&INFO);
OCT_append_string(&INFO,(char *)"res master");
hkdfExpandLabel(htype,&session->RMS,hlen,&MS,&INFO,CFH);
}
// Create Client Cert Verify message, a digital signature using KEY on some TLS1.3 specific message+transcript hash
void createClientCertVerifier(int sigAlg,octad *H,octad *KEY,octad *CCVSIG)
{
char ccv[100+TLS_MAX_HASH];
octad CCV={0,sizeof(ccv),ccv};
// create TLS1.3 message to be signed
OCT_append_byte(&CCV,32,64); // 64 spaces
OCT_append_string(&CCV,(char *)"TLS 1.3, client CertificateVerify"); // 33 chars
OCT_append_byte(&CCV,0,1); // add 0 character
OCT_append_octad(&CCV,H); // add Transcript Hash
if (sigAlg==DILITHIUM2_P256)
{
octad FKEY={32,32,KEY->val};
octad SKEY={KEY->len-32,KEY->len-32,&KEY->val[32]};
SAL_tlsSignature(ECDSA_SECP256R1_SHA384,&FKEY,&CCV,CCVSIG);
ecdsa_sig_encode(CCVSIG); // ASN.1 encode it - it grows
octad SSIG={0,TLS_MAX_SIGNATURE_SIZE-32,&CCVSIG->val[CCVSIG->len]};
SAL_tlsSignature(DILITHIUM2,&SKEY,&CCV,&SSIG); // append PQ sig
CCVSIG->len += SSIG.len;
return;
}
SAL_tlsSignature(sigAlg,KEY,&CCV,CCVSIG);
// adjustment for ECDSA signatures
if (sigAlg==ECDSA_SECP256R1_SHA256 || sigAlg==ECDSA_SECP384R1_SHA384)
{
ecdsa_sig_encode(CCVSIG);
}
return;
}
// check that SCVSIG is digital signature (using sigAlg algorithm) of some TLS1.3 specific message+transcript hash,
// as verified by Server Certificate public key CERTPK
bool checkServerCertVerifier(int sigAlg,octad *SCVSIG,octad *H,octad *CERTPK)
{
// Server Certificate Verify
char scv[100+TLS_MAX_HASH];
octad SCV={0,sizeof(scv),scv};
// TLS1.3 message that was signed
OCT_append_byte(&SCV,32,64); // 64 spaces
OCT_append_string(&SCV,(char *)"TLS 1.3, server CertificateVerify"); // 33 chars
OCT_append_byte(&SCV,0,1); // add 0 character
OCT_append_octad(&SCV,H); // add Transcript Hash
if (sigAlg==DILITHIUM2_P256)
{
octad FPUB={65,65,CERTPK->val};
octad SPUB={CERTPK->len-65,CERTPK->len-65,&CERTPK->val[65]};
int len=SCVSIG->len; // full length
int index=ecdsa_sig_decode(SCVSIG); // ASN.1 decode it - it shrinks - return undecoded length
if (index==0) return false;
int mlen=SCVSIG->len; // modified length
octad FSIG={mlen,mlen,SCVSIG->val};
octad SSIG={len-index,len-index,&SCVSIG->val[index]};
return SAL_tlsSignatureVerify(ECDSA_SECP256R1_SHA384,&SCV,&FSIG,&FPUB) && SAL_tlsSignatureVerify(DILITHIUM2,&SCV,&SSIG,&SPUB);
}
// Special case processing required here for ECDSA signatures - SCVSIG is modified
if (sigAlg==ECDSA_SECP256R1_SHA256 || sigAlg==ECDSA_SECP384R1_SHA384) {
if (!ecdsa_sig_decode(SCVSIG)) return false;
}
log(IO_DEBUG,(char *)"Certificate Signature = ",NULL,0,SCVSIG);
return SAL_tlsSignatureVerify(sigAlg,&SCV,SCVSIG,CERTPK);
}