/* * JS update 14.04.2024 * Pridana podpora pre algoritmy ML-KEM a ML-DSA * Testovane s novou verziou liboqs 0.10.0 */ /* * JS update 29.02.2024 * Doplnene podmienky pre overenie certifikatov podla parametrov pre konkretny PQ algoritmus */ // // TLS1.3 X509 Certificate Processing Code // #include "tls_cert_chain.h" // extract Distinguished Name static void createFullName(octad *FN,octad *CERT,int ic,int len) { OCT_kill(FN); OCT_append_bytes(FN,&CERT->val[ic],len); /* int c,len; OCT_kill(FN); c=X509_find_entity_property(CERT,&X509_MN,ic,&len); OCT_append_bytes(FN,&CERT->val[c],len); OCT_append_byte(FN,'/',1); // spacer c=X509_find_entity_property(CERT,&X509_ON,ic,&len); OCT_append_bytes(FN,&CERT->val[c],len); OCT_append_byte(FN,'/',1); c=X509_find_entity_property(CERT,&X509_UN,ic,&len); OCT_append_bytes(FN,&CERT->val[c],len); */ } // read a line of base64 static int readaline(char *line,const char *rom,int &ptr) { int i=0; if (rom[ptr]==0) return 0; while (rom[ptr]!='\n') { line[i++]=rom[ptr++]; } ptr++; // jump over CR line[i]=0; return i; } // Extract public key from a certificate static pktype getPublicKeyFromCert(octad *CERT,octad *PUBLIC_KEY) { pktype pk=X509_extract_public_key(CERT, PUBLIC_KEY); // pull out its public key return pk; } // extract host name static bool checkHostnameInCert(octad *CERT,char *hostname) { int len; int ic=X509_find_extensions(CERT); int c=X509_find_extension(CERT,&X509_AN,ic,&len); return (bool)X509_find_alt_name(CERT,c,hostname); } // Crude check for certificate validity static bool checkCertNotExpired(octad *CERT) { int ic = X509_find_validity(CERT); int c = X509_find_expiry_date(CERT, ic); int year=2000+(CERT->val[c]-'0')*10 +CERT->val[c+1]-'0'; if (yearval}; octad SPUB={PUBKEY->len-65,PUBKEY->len-65,&PUBKEY->val[65]}; octad FSIG={64,64,SIG->val}; octad SSIG={SIG->len-64,SIG->len-64,&SIG->val[64]}; res = SAL_tlsSignatureVerify(ECDSA_SECP256R1_SHA384,CERT,&FSIG,&FPUB) && SAL_tlsSignatureVerify(DILITHIUM2,CERT,&SSIG,&SPUB); } if (res) { log(IO_DEBUG,(char *)"Cert Signature Verification succeeded \n",NULL,0,NULL); return true; } else { log(IO_DEBUG,(char *)"Cert Signature Verification Failed\n",NULL,0,NULL); return false; } } // Read in raw certificate chain from file, and serialize it for transmission // Read in client private key from .pem file // NOTE: key type can be determined from either the public key or the private key. They should be the same. // Here we get the type from the X.509 private key // What if its a raw public key, and the private key is in hardware? The type is stored along with the cert.. #if CLIENT_CERT != NOCERT int getClientPrivateKeyandCertChain(octad *PRIVKEY,int cert_type,octad *CERTCHAIN) { int i,kind,ptr,len; pktype pk; #ifdef SHALLOW_STACK char *b=(char *)malloc(TLS_MAX_CERT_B64); octad SC={0,TLS_MAX_CERT_B64,b}; // optimization - share memory - can convert from base64 to binary in place #else char b[TLS_MAX_CERT_B64]; // maximum size key/cert octad SC={0,sizeof(b),b}; // share memory - can convert from base64 to binary in place #endif char line[80]; OCT_kill(CERTCHAIN); // should be a chain of certificates, one after the other. May just be one self-signed ptr=0; for (;;) { i=0; if (!readaline(line,mycert,ptr)) break; for (;;) { len=readaline(line,mycert,ptr); if (line[0]=='-') break; for (int j=0;jlen!=0) { // there was one if (!OCT_compare(PREVIOUS_ISSUER,&SUBJECT)) { // Is subject of this cert the issuer of the previous cert? log(IO_DEBUG,(char *)"Subject of this certificate is not issuer of prior certificate\n",NULL,0,NULL); return BAD_CERT_CHAIN; } } OCT_copy(PREVIOUS_ISSUER,&ISSUER); // update issuer return 0; } // extract server public key, and check validity of certificate chain // ensures that the hostname is valid. // Assumes simple chain Server Cert->Intermediate Cert->CA cert // CA cert not read from chain (if its even there). // Search for issuer of Intermediate Cert in cert store int checkServerCertChain(octad *CERTCHAIN,char *hostname,int cert_type,octad *PUBKEY,octad *SERVER_SIG) { ret r; int rtn,len,ptr=0; pktype sst,ist,spt,ipt; // Clever re-use of memory - use pointers into cert chain rather than extracting certs octad SERVER_CERT; // server certificate SERVER_CERT.len=0; octad INTER_CERT; // signature on intermediate certificate INTER_CERT.len=0; char issuer[TLS_X509_MAX_FIELD]; octad ISSUER={0,sizeof(issuer),issuer}; // Extract and process Server Cert r=parseInt(CERTCHAIN,3,ptr); len=r.val; if (r.err) return r.err; // get length of first (server) certificate if (len==0) return EMPTY_CERT_CHAIN; r=parseoctadptr(&SERVER_CERT,len,CERTCHAIN,ptr); if (r.err) return r.err; if (cert_type==RAW_PUBLIC_KEY) { // its not a certificate, its a raw public key. We agreed that this was OK. X509_get_public_key(&SERVER_CERT,PUBKEY); return 0; // NOTE no confirmation of identity } r=parseInt(CERTCHAIN,2,ptr); len=r.val; if (r.err) return r.err; ptr+=len; // skip certificate extensions // Check and parse Server Cert rtn=parseCert(&SERVER_CERT,sst,SERVER_SIG,&ISSUER,spt,PUBKEY); if (rtn != 0) { if (rtn==SELF_SIGNED_CERT) { if (!checkCertSig(sst,&SERVER_CERT,SERVER_SIG,PUBKEY)) { return BAD_CERT_CHAIN; } } else { return rtn; } } // Confirm Identity - public key is associated with this hostname if (!checkHostnameInCert(&SERVER_CERT,hostname) && strcmp(hostname,"localhost")!=0) { // Check that certificate covers the server URL log(IO_PROTOCOL,(char *)"Hostname NOT found in certificate\n",NULL,0,NULL); return BAD_CERT_CHAIN; } if (rtn==SELF_SIGNED_CERT) { #ifdef ALLOW_SELF_SIGNED log(IO_PROTOCOL,(char *)"Self-signed Certificate allowed\n",NULL,0,NULL); return 0; // If self-signed, thats the end of the chain. And for development its acceptable #else return rtn; #endif } if (ptr==CERTCHAIN->len) { log(IO_DEBUG,(char *)"Non-self-signed Chain of length 1 ended unexpectedly\n",NULL,0,NULL); return BAD_CERT_CHAIN; } // Extract and process Intermediate Cert r=parseInt(CERTCHAIN,3,ptr); len=r.val; if (r.err) return r.err; // get length of next certificate if (len==0) return EMPTY_CERT_CHAIN; r=parseoctadptr(&INTER_CERT,len,CERTCHAIN,ptr); if (r.err) return r.err; r=parseInt(CERTCHAIN,2,ptr); len=r.val; if (r.err) return r.err; ptr+=len; // skip certificate extensions if (ptrlen) log(IO_PROTOCOL,(char *)"Warning - there are unprocessed Certificates in the Chain\n",NULL,0,NULL); #ifdef SHALLOW_STACK octad INTER_SIG={0,TLS_MAX_SIGNATURE_SIZE,(char *)malloc(TLS_MAX_SIGNATURE_SIZE)}; octad PK = {0, TLS_MAX_SIG_PUB_KEY_SIZE, (char *)malloc(TLS_MAX_SIG_PUB_KEY_SIZE)}; #else char inter_sig[TLS_MAX_SIGNATURE_SIZE]; // signature on intermediate certificate octad INTER_SIG={0,sizeof(inter_sig),inter_sig}; char pk[TLS_MAX_SIG_PUB_KEY_SIZE]; // Public Key octad PK = {0, sizeof(pk), pk}; #endif // Check and parse Intermediate Cert rtn=parseCert(&INTER_CERT,ist,&INTER_SIG,&ISSUER,ipt,&PK); if (rtn != 0) { #ifdef SHALLOW_STACK free(INTER_SIG.val); free(PK.val); #endif return BAD_CERT_CHAIN; } if (!checkCertSig(sst,&SERVER_CERT,SERVER_SIG,&PK)) { // Check intermediate signature on Server's certificate log(IO_DEBUG,(char *)"Server Certificate sig is NOT OK\n",NULL,0,NULL); #ifdef SHALLOW_STACK free(INTER_SIG.val); free(PK.val); #endif return BAD_CERT_CHAIN; } log(IO_DEBUG,(char *)"Server Certificate sig is OK\n",NULL,0,NULL); // Find Root of Trust // Find root certificate public key if (!findRootCA(&ISSUER,ist,&PK)) { log(IO_DEBUG,(char *)"Root Certificate not found\n",NULL,0,NULL); #ifdef SHALLOW_STACK free(INTER_SIG.val); free(PK.val); #endif return CA_NOT_FOUND; } log(IO_DEBUG,(char *)"\nPublic Key from root cert= ",NULL,0,&PK); if (!checkCertSig(ist,&INTER_CERT,&INTER_SIG,&PK)) { // Check signature on intermediate cert with root cert public key log(IO_DEBUG,(char *)"Root Certificate sig is NOT OK\n",NULL,0,NULL); #ifdef SHALLOW_STACK free(INTER_SIG.val); free(PK.val); #endif return BAD_CERT_CHAIN; } log(IO_DEBUG,(char *)"Root Certificate sig is OK\n",NULL,0,NULL); #ifdef SHALLOW_STACK free(INTER_SIG.val); free(PK.val); #endif return 0; }