567 lines
17 KiB
C++
567 lines
17 KiB
C++
//
|
|
// Process output sent to Server
|
|
//
|
|
|
|
#include "tls_client_send.h"
|
|
#include "tls_logger.h"
|
|
#include "tls_certs.h"
|
|
|
|
// send Change Cipher Suite - helps get past middleboxes (WTF?)
|
|
void sendCCCS(TLS_session *session)
|
|
{
|
|
char cccs[10];
|
|
octad CCCS={0,sizeof(cccs),cccs};
|
|
OCT_from_hex(&CCCS,(char *)"140303000101");
|
|
sendOctad(session->sockptr,&CCCS);
|
|
}
|
|
|
|
// Functions to build clientHello Extensions based on our preferences/capabilities
|
|
|
|
// Build Heartbeat Extension
|
|
void addHeartbeat(octad *EXT)
|
|
{
|
|
OCT_append_int(EXT,HEARTBEAT,2); // This extension is HEARTBEAT
|
|
OCT_append_int(EXT,1,2);
|
|
#ifdef PEER_CAN_HEARTBEAT
|
|
OCT_append_int(EXT,1,1); // peer can heartbeat
|
|
#else
|
|
OCT_append_int(EXT,2,1); // peer cannot heartbeat
|
|
#endif
|
|
}
|
|
|
|
// Build Certificate Authorities Extension
|
|
/*
|
|
void addCertAuthorities(octad *EXT)
|
|
{
|
|
char dn[256];
|
|
octad DN={0,sizeof(dn),dn};
|
|
OCT_from_base64(&DN,(char *)mysupportedca);
|
|
OCT_append_int(EXT,CERT_AUTHORITIES,2);
|
|
OCT_append_int(EXT,DN.len+2,2); // only one CA allowed (for now)
|
|
OCT_append_int(EXT,DN.len,2);
|
|
OCT_append_octad(EXT,&DN);
|
|
}
|
|
*/
|
|
// Build Servername Extension
|
|
void addServerNameExt(octad *EXT,char *servername)
|
|
{
|
|
int len=strlen(servername);
|
|
OCT_append_int(EXT,SERVER_NAME,2); // This extension is SERVER_NAME(0)
|
|
OCT_append_int(EXT,5+len,2); // In theory its a list..
|
|
OCT_append_int(EXT,3+len,2); // but only one entry
|
|
OCT_append_int(EXT,0,1); // Server is of type DNS Hostname (only one type supported, and only one of each type)
|
|
OCT_append_int(EXT,len,2); // serverName length
|
|
OCT_append_string(EXT,servername); // servername
|
|
}
|
|
|
|
// Build Supported Groups Extension
|
|
void addSupportedGroupsExt(octad *EXT,int nsg,int *supportedGroups)
|
|
{
|
|
OCT_append_int(EXT,SUPPORTED_GROUPS,2); // This extension is SUPPORTED GROUPS(0x0a)
|
|
OCT_append_int(EXT,2*nsg+2,2); // Total length
|
|
OCT_append_int(EXT,2*nsg,2); // Number of entries
|
|
for (int i=0;i<nsg;i++) // One entry per supported group
|
|
OCT_append_int(EXT,supportedGroups[i],2);
|
|
}
|
|
|
|
// Build client cert type extension for raw public key
|
|
void addClientRawPublicKey(octad *EXT)
|
|
{
|
|
OCT_append_int(EXT,CLIENT_CERT_TYPE,2);
|
|
OCT_append_int(EXT,3,2);
|
|
OCT_append_int(EXT,2,1);
|
|
OCT_append_int(EXT,RAW_PUBLIC_KEY,1);
|
|
OCT_append_int(EXT,X509_CERT,1);
|
|
}
|
|
|
|
// Build server cert type extension for raw public key
|
|
void addServerRawPublicKey(octad *EXT)
|
|
{
|
|
OCT_append_int(EXT,SERVER_CERT_TYPE,2);
|
|
OCT_append_int(EXT,3,2);
|
|
OCT_append_int(EXT,2,1);
|
|
OCT_append_int(EXT,RAW_PUBLIC_KEY,1);
|
|
OCT_append_int(EXT,X509_CERT,1);
|
|
}
|
|
|
|
// Build Signature algorithms Extension
|
|
void addSigAlgsExt(octad *EXT,int nsa,int *sigAlgs)
|
|
{
|
|
OCT_append_int(EXT,SIG_ALGS,2); // This extension is SIGNATURE_ALGORITHMS(0x0d)
|
|
OCT_append_int(EXT,2*nsa+2,2); // Total length
|
|
OCT_append_int(EXT,2*nsa,2); // Number of entries
|
|
for (int i=0;i<nsa;i++) // One entry per supported signature algorithm
|
|
OCT_append_int(EXT,sigAlgs[i],2);
|
|
}
|
|
|
|
// Build Signature algorithms Cert Extension
|
|
void addSigAlgsCertExt(octad *EXT,int nsac,int *sigAlgsCert)
|
|
{
|
|
OCT_append_int(EXT,SIG_ALGS_CERT,2); // This extension is SIGNATURE_ALGORITHMS_CERT (0x32)
|
|
OCT_append_int(EXT,2*nsac+2,2); // Total length
|
|
OCT_append_int(EXT,2*nsac,2); // Number of entries
|
|
for (int i=0;i<nsac;i++) // One entry per supported signature algorithm
|
|
OCT_append_int(EXT,sigAlgsCert[i],2);
|
|
}
|
|
|
|
// Add Pre-Shared-Key ...
|
|
// ..but omit binding
|
|
int addPreSharedKeyExt(octad *EXT,unsign32 age,octad *IDS,int sha)
|
|
{
|
|
int tlen1,tlen2;
|
|
tlen1=tlen2=0;
|
|
tlen1+=IDS->len+2+4;
|
|
tlen2+=sha+1;
|
|
OCT_append_int(EXT,PRESHARED_KEY,2);
|
|
OCT_append_int(EXT,tlen1+tlen2+4,2);
|
|
// PSK Identifiers
|
|
OCT_append_int(EXT,tlen1,2);
|
|
OCT_append_int(EXT,IDS->len,2);
|
|
OCT_append_octad(EXT,IDS);
|
|
OCT_append_int(EXT,age,4);
|
|
return tlen2+2; // length of binders
|
|
}
|
|
|
|
// Add Client Key Share extension
|
|
// Offer just one public key
|
|
void addKeyShareExt(octad *EXT,int alg,octad *PK)
|
|
{
|
|
int tlen=PK->len+4;
|
|
OCT_append_int(EXT,KEY_SHARE,2); // This extension is KEY_SHARE(0x0033)
|
|
OCT_append_int(EXT,tlen+2,2);
|
|
OCT_append_int(EXT,tlen,2);
|
|
OCT_append_int(EXT,alg,2);
|
|
OCT_append_int(EXT,PK->len,2);
|
|
OCT_append_octad(EXT,PK);
|
|
}
|
|
|
|
// Add ALPN extension
|
|
// Offer just one option
|
|
void addALPNExt(octad *EXT,octad *AP)
|
|
{
|
|
int tlen=AP->len+1;
|
|
OCT_append_int(EXT,APP_PROTOCOL,2);
|
|
OCT_append_int(EXT,tlen+2,2);
|
|
OCT_append_int(EXT,tlen,2);
|
|
OCT_append_int(EXT,AP->len,1);
|
|
OCT_append_octad(EXT,AP);
|
|
}
|
|
|
|
// indicate supported PSK mode
|
|
void addPSKModesExt(octad *EXT,int mode)
|
|
{
|
|
OCT_append_int(EXT,PSK_MODE,2);
|
|
OCT_append_int(EXT,2,2);
|
|
OCT_append_int(EXT,1,1);
|
|
OCT_append_int(EXT,mode,1);
|
|
}
|
|
|
|
// indicate preferred maximum fragment length
|
|
void addMFLExt(octad *EXT,int mode)
|
|
{
|
|
if (mode>0)
|
|
{
|
|
OCT_append_int(EXT,MAX_FRAG_LENGTH,2);
|
|
OCT_append_int(EXT,1,2);
|
|
OCT_append_int(EXT,mode,1);
|
|
}
|
|
}
|
|
|
|
// indicate preferred maximum record size
|
|
void addRSLExt(octad *EXT,int size)
|
|
{
|
|
OCT_append_int(EXT,RECORD_SIZE_LIMIT,2);
|
|
OCT_append_int(EXT,2,2);
|
|
OCT_append_int(EXT,size,2);
|
|
}
|
|
|
|
// add n padding bytes
|
|
void addPadding(octad *EXT,int n)
|
|
{
|
|
OCT_append_int(EXT,PADDING,2);
|
|
OCT_append_int(EXT,n,2);
|
|
OCT_append_byte(EXT,0,n);
|
|
}
|
|
|
|
// indicate TLS version support
|
|
void addVersionExt(octad *EXT,int version)
|
|
{
|
|
OCT_append_int(EXT,TLS_VER,2);
|
|
OCT_append_int(EXT,3,2);
|
|
OCT_append_int(EXT,2,1);
|
|
OCT_append_int(EXT,version,2);
|
|
}
|
|
|
|
// Add a cookie - useful for handshake resumption
|
|
void addCookieExt(octad *EXT,octad *CK)
|
|
{
|
|
OCT_append_int(EXT,COOKIE,2);
|
|
OCT_append_int(EXT,CK->len,2);
|
|
OCT_append_octad(EXT,CK);
|
|
}
|
|
|
|
// indicate desire to send early data
|
|
void addEarlyDataExt(octad *EXT)
|
|
{
|
|
OCT_append_int(EXT,EARLY_DATA,2);
|
|
OCT_append_int(EXT,0,2);
|
|
}
|
|
|
|
// indicate willingness to do post handshake authentication
|
|
void addPostHSAuth(octad *EXT)
|
|
{
|
|
OCT_append_int(EXT,POST_HANDSHAKE_AUTH,2);
|
|
OCT_append_int(EXT,0,2);
|
|
}
|
|
|
|
// build cipher-suites octad from ciphers we support
|
|
int cipherSuites(octad *CS,int ncs,int *ciphers)
|
|
{
|
|
OCT_kill(CS);
|
|
OCT_append_int(CS,2*ncs,2);
|
|
for (int i=0;i<ncs;i++)
|
|
OCT_append_int(CS,ciphers[i],2);
|
|
return CS->len;
|
|
}
|
|
|
|
void sendZeroRecord(TLS_session *session) {
|
|
char rh[5];
|
|
char tag[TLS_MAX_TAG_SIZE];
|
|
octad TAG={0,sizeof(tag),tag};
|
|
int taglen=session->K_send.taglen;
|
|
int ctlen=TLS_MAX_OUTPUT_RECORD_SIZE+1;
|
|
int reclen=ctlen+taglen;
|
|
rh[0]=APPLICATION;
|
|
rh[1]=(TLS1_2/256);
|
|
rh[2]=(TLS1_2%256);
|
|
rh[3]=(reclen/256);
|
|
rh[4]=(reclen%256);
|
|
|
|
session->OBUFF.val[5]=APPLICATION;
|
|
session->OBUFF.len=ctlen+5;
|
|
|
|
SAL_aeadEncrypt(&session->K_send,5,rh,ctlen,&session->OBUFF.val[5],&TAG);
|
|
incrementCryptoContext(&session->K_send); // increment IV
|
|
OCT_append_octad(&session->OBUFF,&TAG);
|
|
|
|
for (int j=0;j<5;j++)
|
|
session->OBUFF.val[j]=rh[j];
|
|
|
|
sendOctad(session->sockptr,&session->OBUFF); // transmit it
|
|
OCT_kill(&session->OBUFF); // empty it
|
|
session->OBUFF.len=5;
|
|
}
|
|
|
|
// send one or more records, maybe encrypted.
|
|
void sendRecord(TLS_session *session,int rectype,int version,octad *DATA,bool flush) {
|
|
char rh[5];
|
|
int alen;
|
|
if (session->OBUFF.len==0)
|
|
{ // first time - reserve 5 spaces for header
|
|
session->OBUFF.len=5;
|
|
alen=0;
|
|
} else {
|
|
alen=session->OBUFF.len-5; // payload length
|
|
}
|
|
|
|
for (int i=0;i<DATA->len;i++) {
|
|
OCT_append_byte(&session->OBUFF,DATA->val[i],1); alen++;
|
|
bool flushing=false;
|
|
if (i==DATA->len-1 && flush) flushing=true;;
|
|
if (alen==TLS_MAX_OUTPUT_RECORD_SIZE || flushing)
|
|
{
|
|
int reclen,ctlen;
|
|
if (!session->K_send.active) { // no encryption
|
|
reclen=alen;
|
|
rh[0]=rectype;
|
|
rh[1]=(version/256);
|
|
rh[2]=(version%256);
|
|
rh[3]=(reclen/256);
|
|
rh[4]=(reclen%256);
|
|
} else {
|
|
char tag[TLS_MAX_TAG_SIZE];
|
|
octad TAG={0,sizeof(tag),tag};
|
|
int taglen=session->K_send.taglen;
|
|
OCT_append_byte(&session->OBUFF,rectype,1);
|
|
#ifdef PAD_SHORT_RECORDS
|
|
ctlen=TLS_MAX_OUTPUT_RECORD_SIZE+1; // pad to full length - should be padded with 0s
|
|
session->OBUFF.len=ctlen+5;
|
|
#else
|
|
ctlen=alen+1;
|
|
#endif
|
|
reclen=ctlen+taglen;
|
|
rh[0]=APPLICATION;
|
|
rh[1]=(TLS1_2/256);
|
|
rh[2]=(TLS1_2%256);
|
|
rh[3]=(reclen/256);
|
|
rh[4]=(reclen%256);
|
|
|
|
SAL_aeadEncrypt(&session->K_send,5,rh,ctlen,&session->OBUFF.val[5],&TAG);
|
|
incrementCryptoContext(&session->K_send); // increment IV
|
|
OCT_append_octad(&session->OBUFF,&TAG);
|
|
}
|
|
for (int j=0;j<5;j++)
|
|
session->OBUFF.val[j]=rh[j];
|
|
|
|
sendOctad(session->sockptr,&session->OBUFF); // transmit it
|
|
OCT_kill(&session->OBUFF); // empty it
|
|
alen=0;
|
|
session->OBUFF.len=5;
|
|
}
|
|
if (flushing) session->OBUFF.len=0;
|
|
}
|
|
}
|
|
|
|
|
|
// ALL Client to Server output goes via this function
|
|
// Send a client message CM|EXT (as a single record).
|
|
// Only transmit (flush) on a key change, or end of pass
|
|
void sendClientMessage(TLS_session *session,int rectype,int version,octad *CM,octad *EXT,bool flush)
|
|
{
|
|
if (session->status==TLS13_DISCONNECTED) {
|
|
return;
|
|
}
|
|
|
|
bool choice=flush;
|
|
#ifndef MERGE_MESSAGES
|
|
choice=true;
|
|
#endif
|
|
if (EXT!=NULL)
|
|
{
|
|
sendRecord(session,rectype,version,CM,false);
|
|
sendRecord(session,rectype,version,EXT,choice);
|
|
} else {
|
|
sendRecord(session,rectype,version,CM,choice);
|
|
}
|
|
}
|
|
|
|
// Send a heartbeat request record. Note my payloads are always of length 0.
|
|
// should it be encrypted? Yes
|
|
void sendHeartbeatRequest(TLS_session *session)
|
|
{
|
|
char hb[20];
|
|
octad HB={0,sizeof(hb),hb};
|
|
if (session->status==TLS13_DISCONNECTED || !session->allowed_to_heartbeat || session->heartbeat_req_in_flight) {
|
|
return;
|
|
}
|
|
//printf("Sending HEART_BEAT REQ\n");
|
|
OCT_append_int(&HB,1,1); // heartbeat request
|
|
OCT_append_int(&HB,0,2); // zero payload
|
|
for (int i=0;i<16;i++)
|
|
OCT_append_int(&HB,SAL_randomByte(),1);
|
|
session->heartbeat_req_in_flight=true;
|
|
sendRecord(session,HEART_BEAT,TLS1_2,&HB,true);
|
|
}
|
|
|
|
|
|
// build and transmit unencrypted client hello. Append pre-prepared extensions
|
|
void sendClientHello(TLS_session *session,int version,octad *CH,octad *CRN,bool already_agreed,octad *EXTENSIONS,int extra,bool resume,bool flush)
|
|
{
|
|
char cs[2+TLS_MAX_CIPHER_SUITES*2];
|
|
octad CS = {0, sizeof(cs), cs};
|
|
int nsc;
|
|
int ciphers[TLS_MAX_CIPHER_SUITES];
|
|
int compressionMethods=0x0100;
|
|
int total=8;
|
|
int extlen=EXTENSIONS->len+extra;
|
|
|
|
nsc=SAL_ciphers(ciphers);
|
|
if (already_agreed)
|
|
{ // cipher suite already agreed
|
|
nsc=1;
|
|
ciphers[0]=session->cipher_suite;
|
|
}
|
|
|
|
total+=32; // Random bytes clientRandom(&RN);
|
|
total+=33;
|
|
if (!resume) { // if its a handshake resumption, re-use the old id?? Since its the same session?
|
|
for (int i=0;i<32;i++)
|
|
session->id[i]=SAL_randomByte();
|
|
}
|
|
|
|
total+=cipherSuites(&CS,nsc,ciphers);
|
|
|
|
OCT_kill(CH);
|
|
OCT_append_byte(CH,CLIENT_HELLO,1); // clientHello handshake message // 1
|
|
OCT_append_int(CH,total+extlen-2,3); // 3
|
|
|
|
OCT_append_int(CH,TLS1_2,2); // 2
|
|
OCT_append_octad(CH,CRN); // 32
|
|
OCT_append_byte(CH,32,1); // 1
|
|
OCT_append_bytes(CH,session->id,32); // 32
|
|
OCT_append_octad(CH,&CS); // 2+TLS_MAX_CIPHER_SUITES*2
|
|
OCT_append_int(CH,compressionMethods,2); // 2
|
|
OCT_append_int(CH,extlen,2); // 2
|
|
|
|
// transmit it
|
|
sendClientMessage(session,HSHAKE,version,CH,EXTENSIONS,flush);
|
|
}
|
|
|
|
// Send "binder",
|
|
void sendBinder(TLS_session *session,octad *BND)
|
|
{
|
|
char b[TLS_MAX_HASH+3];
|
|
octad B={0,sizeof(b),b};
|
|
int tlen2=BND->len+1;
|
|
//OCT_kill(B);
|
|
OCT_append_int(&B,tlen2,2);
|
|
OCT_append_int(&B,BND->len,1);
|
|
OCT_append_octad(&B,BND);
|
|
runningHash(session,&B);
|
|
sendClientMessage(session,HSHAKE,TLS1_2,&B,NULL,true);
|
|
}
|
|
|
|
// send client alert - might be encrypted if send!=NULL
|
|
void sendAlert(TLS_session *session,int type)
|
|
{
|
|
char pt[2];
|
|
octad PT={0,sizeof(pt),pt};
|
|
OCT_append_byte(&PT,0x02,1); // alerts are always fatal
|
|
OCT_append_byte(&PT,type,1); // alert type
|
|
OCT_kill(&session->IBUFF); session->ptr=0;
|
|
sendClientMessage(session,ALERT,TLS1_2,&PT,NULL,true);
|
|
if (session->status!=TLS13_DISCONNECTED)
|
|
{
|
|
log(IO_PROTOCOL,(char *)"Alert sent to Server - ",NULL,0,NULL);
|
|
logAlert(type);
|
|
}
|
|
session->status=TLS13_DISCONNECTED; // write side of connection is now off
|
|
}
|
|
|
|
void sendKeyUpdate(TLS_session *session,int type)
|
|
{
|
|
char up[5];
|
|
octad UP={0,sizeof(up),up};
|
|
OCT_append_byte(&UP,KEY_UPDATE,1);
|
|
OCT_append_int(&UP,1,3);
|
|
OCT_append_int(&UP,type,1);
|
|
OCT_kill(&session->IBUFF); session->ptr=0;
|
|
sendClientMessage(session,HSHAKE,TLS1_2,&UP,NULL,true); // sent using old keys
|
|
deriveUpdatedKeys(&session->K_send,&session->CTS); // now update keys
|
|
log(IO_PROTOCOL,(char *)"KEY UPDATE REQUESTED\n",NULL,0,NULL);
|
|
}
|
|
|
|
// Send final client handshake verification data
|
|
void sendClientFinish(TLS_session *session,octad *CHF)
|
|
{
|
|
char pt[4];
|
|
octad PT={0,sizeof(pt),pt};
|
|
|
|
OCT_append_byte(&PT,FINISHED,1); // indicates handshake message "client finished"
|
|
OCT_append_int(&PT,CHF->len,3); // .. and its length
|
|
|
|
runningHash(session,&PT);
|
|
runningHash(session,CHF);
|
|
sendClientMessage(session,HSHAKE,TLS1_2,&PT,CHF,true); // now we can flush
|
|
}
|
|
|
|
/* Send Client Cert Verify */
|
|
void sendClientCertVerify(TLS_session *session, int sigAlg, octad *CCVSIG)
|
|
{
|
|
char pt[10];
|
|
octad PT={0,sizeof(pt),pt};
|
|
OCT_append_byte(&PT,CERT_VERIFY,1);
|
|
OCT_append_int(&PT,4+CCVSIG->len,3);
|
|
OCT_append_int(&PT,sigAlg,2);
|
|
OCT_append_int(&PT,CCVSIG->len,2);
|
|
runningHash(session,&PT);
|
|
runningHash(session,CCVSIG);
|
|
sendClientMessage(session,HSHAKE,TLS1_2,&PT,CCVSIG,false);
|
|
}
|
|
|
|
// Send Client Certificate
|
|
void sendClientCertificateChain(TLS_session *session,octad *CERTCHAIN)
|
|
{
|
|
char pt[50];
|
|
octad PT={0,sizeof(pt),pt};
|
|
|
|
OCT_append_byte(&PT,CERTIFICATE,1);
|
|
if (CERTCHAIN==NULL) { // no acceptable certificate available
|
|
OCT_append_int(&PT,4,3);
|
|
int nb=session->CTX.len;
|
|
OCT_append_byte(&PT,nb,1); // cert context
|
|
if (nb>0)
|
|
OCT_append_octad(&PT,&session->CTX);
|
|
OCT_append_int(&PT,0,3); // zero length
|
|
runningHash(session,&PT);
|
|
sendClientMessage(session,HSHAKE,TLS1_2,&PT,NULL,true);
|
|
} else {
|
|
OCT_append_int(&PT,4+CERTCHAIN->len,3);
|
|
int nb=session->CTX.len;
|
|
OCT_append_byte(&PT,nb,1); // cert context
|
|
if (nb>0)
|
|
OCT_append_octad(&PT,&session->CTX);
|
|
OCT_append_int(&PT,CERTCHAIN->len,3); // length of certificate chain
|
|
runningHash(session,&PT);
|
|
runningHash(session,CERTCHAIN);
|
|
sendClientMessage(session,HSHAKE,TLS1_2,&PT,CERTCHAIN,false);
|
|
|
|
}
|
|
}
|
|
|
|
// if early data was accepted, send this to indicate early data is finished
|
|
void sendEndOfEarlyData(TLS_session *session)
|
|
{
|
|
char ed[4];
|
|
octad ED={0,sizeof(ed),ed};
|
|
OCT_append_byte(&ED,END_OF_EARLY_DATA,1);
|
|
OCT_append_int(&ED,0,3);
|
|
runningHash(session,&ED);
|
|
sendClientMessage(session,HSHAKE,TLS1_2,&ED,NULL,true); // change of encryption keys coming, so flush
|
|
}
|
|
|
|
//
|
|
// map causes to alerts
|
|
//
|
|
int alert_from_cause(int rtn)
|
|
{
|
|
switch (rtn)
|
|
{
|
|
case NOT_TLS1_3:
|
|
return ILLEGAL_PARAMETER;
|
|
case ID_MISMATCH:
|
|
return ILLEGAL_PARAMETER;
|
|
case UNRECOGNIZED_EXT:
|
|
return ILLEGAL_PARAMETER;
|
|
case BAD_HELLO:
|
|
return ILLEGAL_PARAMETER;
|
|
case WRONG_MESSAGE: // Cause
|
|
return UNEXPECTED_MESSAGE; // Alert
|
|
case BAD_CERT_CHAIN: // Cause
|
|
return BAD_CERTIFICATE; // Alert
|
|
case MISSING_REQUEST_CONTEXT:
|
|
return ILLEGAL_PARAMETER;
|
|
case AUTHENTICATION_FAILURE:
|
|
return BAD_RECORD_MAC;
|
|
case BAD_RECORD:
|
|
return DECODE_ERROR;
|
|
case BAD_TICKET:
|
|
return ILLEGAL_PARAMETER;
|
|
case NOT_EXPECTED:
|
|
return UNSUPPORTED_EXTENSION;
|
|
case CA_NOT_FOUND:
|
|
return UNKNOWN_CA;
|
|
case CERT_OUTOFDATE:
|
|
return CERTIFICATE_EXPIRED;
|
|
case MEM_OVERFLOW:
|
|
return DECODE_ERROR;
|
|
case FORBIDDEN_EXTENSION:
|
|
return ILLEGAL_PARAMETER;
|
|
case MAX_EXCEEDED:
|
|
return RECORD_OVERFLOW;
|
|
case CERT_VERIFY_FAIL:
|
|
return DECRYPT_ERROR;
|
|
case BAD_HANDSHAKE:
|
|
return HANDSHAKE_FAILURE;
|
|
case BAD_REQUEST_UPDATE:
|
|
return ILLEGAL_PARAMETER;
|
|
case MISSING_EXTENSIONS:
|
|
return MISSING_EXTENSION;
|
|
case BAD_MESSAGE:
|
|
case EMPTY_CERT_CHAIN:
|
|
return DECODE_ERROR;
|
|
default:
|
|
return ILLEGAL_PARAMETER;
|
|
}
|
|
}
|