void tlsFree(TlsContext *context) { //Invalid TLS context? if(context == NULL) return; //Properly close the TLS session by sending a close notify tlsShutdown(context); //Release server name osFreeMem(context->serverName); //Free Diffie-Hellman context dhFree(&context->dhContext); //Free ECDH context ecdhFree(&context->ecdhContext); //Release peer's RSA public key rsaFreePublicKey(&context->peerRsaPublicKey); //Release peer's DSA public key dsaFreePublicKey(&context->peerDsaPublicKey); //Release peer's EC domain parameters ecFreeDomainParameters(&context->peerEcParams); //Release peer's EC public key ecFree(&context->peerEcPublicKey); //Release send buffer memset(context->txBuffer, 0, TLS_TX_BUFFER_SIZE); osFreeMem(context->txBuffer); //Release receive buffer memset(context->rxBuffer, 0, TLS_RX_BUFFER_SIZE); osFreeMem(context->rxBuffer); //Release resources used to compute handshake message hash osFreeMem(context->handshakeMd5Context); osFreeMem(context->handshakeSha1Context); osFreeMem(context->handshakeHashContext); //Release the write encryption context if(context->writeCipherContext) { //Clear context contents, then release memory memset(context->writeCipherContext, 0, context->cipherAlgo->contextSize); osFreeMem(context->writeCipherContext); } //Release the read encryption context if(context->readCipherContext) { //Clear context contents, then release memory memset(context->readCipherContext, 0, context->cipherAlgo->contextSize); osFreeMem(context->readCipherContext); } //Clear the TLS context before freeing memory memset(context, 0, sizeof(TlsContext)); osFreeMem(context); }
void ecFreeDomainParameters(EcDomainParameters *params) { //Release previsoulsy allocated resources mpiFree(¶ms->p); mpiFree(¶ms->a); mpiFree(¶ms->b); ecFree(¶ms->g); mpiFree(¶ms->q); }
error_t ecFullSub(const EcDomainParameters *params, EcPoint *r, const EcPoint *s, const EcPoint *t) { error_t error; EcPoint u; //Initialize EC point ecInit(&u); //Set Ux = Tx and Uz = Tz MPI_CHECK(mpiCopy(&u.x, &t->x)); MPI_CHECK(mpiCopy(&u.z, &t->z)); //Set Uy = p - Ty MPI_CHECK(mpiSub(&u.y, ¶ms->p, &t->y)); //Compute R = S + U EC_CHECK(ecFullAdd(params, r, s, &u)); end: //Release EC point ecFree(&u); //Return status code return error; }
error_t ecTwinMult(const EcDomainParameters *params, EcPoint *r, const Mpi *d0, const EcPoint *s, const Mpi *d1, const EcPoint *t) { error_t error; int_t k; uint_t m; uint_t m0; uint_t m1; uint_t c0; uint_t c1; uint_t h0; uint_t h1; int_t u0; int_t u1; EcPoint spt; EcPoint smt; //Initialize EC points ecInit(&spt); ecInit(&smt); //Precompute SpT = S + T EC_CHECK(ecFullAdd(params, &spt, s, t)); //Precompute SmT = S - T EC_CHECK(ecFullSub(params, &smt, s, t)); //Let m0 be the bit length of d0 m0 = mpiGetBitLength(d0); //Let m1 be the bit length of d1 m1 = mpiGetBitLength(d1); //Let m = MAX(m0, m1) m = MAX(m0, m1); //Let c be a 2 x 6 binary matrix c0 = mpiGetBitValue(d0, m - 4); c0 |= mpiGetBitValue(d0, m - 3) << 1; c0 |= mpiGetBitValue(d0, m - 2) << 2; c0 |= mpiGetBitValue(d0, m - 1) << 3; c1 = mpiGetBitValue(d1, m - 4); c1 |= mpiGetBitValue(d1, m - 3) << 1; c1 |= mpiGetBitValue(d1, m - 2) << 2; c1 |= mpiGetBitValue(d1, m - 1) << 3; //Set R = (1, 1, 0) MPI_CHECK(mpiSetValue(&r->x, 1)); MPI_CHECK(mpiSetValue(&r->y, 1)); MPI_CHECK(mpiSetValue(&r->z, 0)); //Calculate both multiplications at the same time for(k = m; k >= 0; k--) { //Compute h(0) = 16 * c(0,1) + 8 * c(0,2) + 4 * c(0,3) + 2 * c(0,4) + c(0,5) h0 = c0 & 0x1F; //Check whether c(0,0) == 1 if(c0 & 0x20) h0 = 31 - h0; //Compute h(1) = 16 * c(1,1) + 8 * c(1,2) + 4 * c(1,3) + 2 * c(1,4) + c(1,5) h1 = c1 & 0x1F; //Check whether c(1,0) == 1 if(c1 & 0x20) h1 = 31 - h1; //Compute u(0) if(h0 < ecTwinMultF(h1)) u0 = 0; else if(c0 & 0x20) u0 = -1; else u0 = 1; //Compute u(1) if(h1 < ecTwinMultF(h0)) u1 = 0; else if(c1 & 0x20) u1 = -1; else u1 = 1; //Update c matrix c0 <<= 1; c0 |= mpiGetBitValue(d0, k - 5); c0 ^= u0 ? 0x20 : 0x00; c1 <<= 1; c1 |= mpiGetBitValue(d1, k - 5); c1 ^= u1 ? 0x20 : 0x00; //Point doubling EC_CHECK(ecDouble(params, r, r)); //Check u(0) and u(1) if(u0 == -1 && u1 == -1) { //Compute R = R - SpT EC_CHECK(ecFullSub(params, r, r, &spt)); } else if(u0 == -1 && u1 == 0) { //Compute R = R - S EC_CHECK(ecFullSub(params, r, r, s)); } else if(u0 == -1 && u1 == 1) { //Compute R = R - SmT EC_CHECK(ecFullSub(params, r, r, &smt)); } else if(u0 == 0 && u1 == -1) { //Compute R = R - T EC_CHECK(ecFullSub(params, r, r, t)); } else if(u0 == 0 && u1 == 1) { //Compute R = R + T EC_CHECK(ecFullAdd(params, r, r, t)); } else if(u0 == 1 && u1 == -1) { //Compute R = R + SmT EC_CHECK(ecFullAdd(params, r, r, &smt)); } else if(u0 == 1 && u1 == 0) { //Compute R = R + S EC_CHECK(ecFullAdd(params, r, r, s)); } else if(u0 == 1 && u1 == 1) { //Compute R = R + SpT EC_CHECK(ecFullAdd(params, r, r, &spt)); } } end: //Release EC points ecFree(&spt); ecFree(&smt); //Return status code return error; }
error_t tlsParseCertificate(TlsContext *context, const TlsCertificate *message, size_t length) { error_t error; const uint8_t *p; size_t n; const char_t *pemCert; size_t pemCertLength; uint8_t *derCert; size_t derCertSize; size_t derCertLength; //X.509 certificates X509CertificateInfo *certInfo = NULL; X509CertificateInfo *issuerCertInfo = NULL; //Debug message TRACE_INFO("Certificate message received (%" PRIuSIZE " bytes)...\r\n", length); TRACE_DEBUG_ARRAY(" ", message, length); //Check the length of the Certificate message if(length < sizeof(TlsCertificate)) return ERROR_DECODING_FAILED; //TLS operates as a client or a server? if(context->entity == TLS_CONNECTION_END_CLIENT) { //Check current state if(context->state != TLS_STATE_SERVER_CERTIFICATE) return ERROR_UNEXPECTED_MESSAGE; } else { //Check current state if(context->state != TLS_STATE_CLIENT_CERTIFICATE) return ERROR_UNEXPECTED_MESSAGE; } //Update the hash value with the incoming handshake message tlsUpdateHandshakeHash(context, message, length); //Get the size occupied by the certificate list n = LOAD24BE(message->certificateListLength); //Remaining bytes to process length -= sizeof(TlsCertificate); //Ensure that the chain of certificates is valid if(n > length) return ERROR_DECODING_FAILED; //Compute the length of the certificate list length = n; //The sender's certificate must come first in the list p = message->certificateList; //Start of exception handling block do { //Assume an error... error = ERROR_OUT_OF_MEMORY; //Allocate a memory buffer to store X.509 certificate info certInfo = osAllocMem(sizeof(X509CertificateInfo)); //Failed to allocate memory? if(!certInfo) break; //Allocate a memory buffer to store the parent certificate issuerCertInfo = osAllocMem(sizeof(X509CertificateInfo)); //Failed to allocate memory? if(!issuerCertInfo) break; //TLS operates as a server? if(context->entity == TLS_CONNECTION_END_SERVER) { //Empty certificate list? if(!length) { //Check whether mutual authentication is required if(context->clientAuthMode == TLS_CLIENT_AUTH_REQUIRED) { //If client authentication is required by the server for the handshake //to continue, it may respond with a fatal handshake failure alert error = ERROR_HANDSHAKE_FAILED; break; } else { //Client authentication is optional context->peerCertType = TLS_CERT_NONE; //Exit immediately error = NO_ERROR; break; } } } //Each certificate is preceded by a 3-byte length field if(length < 3) { //Report an error error = ERROR_DECODING_FAILED; break; } //Get the size occupied by the certificate n = LOAD24BE(p); //Jump to the beginning of the DER encoded certificate p += 3; length -= 3; //Make sure that the certificate is valid if(n > length) { //Report an error error = ERROR_DECODING_FAILED; break; } //Display ASN.1 structure error = asn1DumpObject(p, n, 0); //Any error to report? if(error) break; //Parse X.509 certificate error = x509ParseCertificate(p, n, certInfo); //Failed to parse the X.509 certificate? if(error) break; #if (TLS_CLIENT_SUPPORT == ENABLED) //TLS operates as a client? if(context->entity == TLS_CONNECTION_END_CLIENT) { //Check if the hostname must be verified if(context->serverName != NULL) { //Point to the last character of the common name int_t i = certInfo->subject.commonNameLen - 1; //Point to the last character of the hostname int_t j = strlen(context->serverName) - 1; //Check the common name in the server certificate against //the actual hostname that is being requested while(i >= 0 && j >= 0) { //Wildcard certificate found? if(certInfo->subject.commonName[i] == '*' && i == 0) { //The CN is acceptable j = 0; } //Perform case insensitive character comparison else if(tolower((uint8_t) certInfo->subject.commonName[i]) != context->serverName[j]) { break; } //Compare previous characters i--; j--; } //If the host names do not match, reject the certificate if(i >= 0 || j >= 0) { //Debug message TRACE_WARNING("Server name mismatch!\r\n"); //Report an error error = ERROR_BAD_CERTIFICATE; break; } } } #endif //The certificate contains a valid RSA public key? if(!oidComp(certInfo->subjectPublicKeyInfo.oid, certInfo->subjectPublicKeyInfo.oidLen, RSA_ENCRYPTION_OID, sizeof(RSA_ENCRYPTION_OID))) { //Retrieve the RSA public key error = x509ReadRsaPublicKey(certInfo, &context->peerRsaPublicKey); //Any error to report if(error) break; //Save the certificate type context->peerCertType = TLS_CERT_RSA_SIGN; } //The certificate contains a valid DSA public key? else if(!oidComp(certInfo->subjectPublicKeyInfo.oid, certInfo->subjectPublicKeyInfo.oidLen, DSA_OID, sizeof(DSA_OID))) { //Retrieve the DSA public key error = x509ReadDsaPublicKey(certInfo, &context->peerDsaPublicKey); //Any error to report if(error) break; //Save the certificate type context->peerCertType = TLS_CERT_DSS_SIGN; } //The certificate contains a valid EC public key? else if(!oidComp(certInfo->subjectPublicKeyInfo.oid, certInfo->subjectPublicKeyInfo.oidLen, EC_PUBLIC_KEY_OID, sizeof(EC_PUBLIC_KEY_OID))) { const EcCurveInfo *curveInfo; //Retrieve EC domain parameters curveInfo = ecGetCurveInfo(certInfo->subjectPublicKeyInfo.ecParams.namedCurve, certInfo->subjectPublicKeyInfo.ecParams.namedCurveLen); //Make sure the specified elliptic curve is supported if(curveInfo == NULL) { //Report an error error = ERROR_BAD_CERTIFICATE; //Exit immediately break; } //Load EC domain parameters error = ecLoadDomainParameters(&context->peerEcParams, curveInfo); //Any error to report? if(error) break; //Retrieve the EC public key error = ecImport(&context->peerEcParams, &context->peerEcPublicKey, certInfo->subjectPublicKeyInfo.ecPublicKey.q, certInfo->subjectPublicKeyInfo.ecPublicKey.qLen); //Any error to report if(error) break; //Save the certificate type context->peerCertType = TLS_CERT_ECDSA_SIGN; } //The certificate does not contain any valid public key? else { //Report an error error = ERROR_BAD_CERTIFICATE; break; } //Next certificate p += n; length -= n; //PKIX path validation while(length > 0) { //Each certificate is preceded by a 3-byte length field if(length < 3) { //Report an error error = ERROR_DECODING_FAILED; break; } //Get the size occupied by the certificate n = LOAD24BE(p); //Jump to the beginning of the DER encoded certificate p += 3; length -= 3; //Ensure that the certificate is valid if(n > length) { //Report an error error = ERROR_DECODING_FAILED; break; } //Display ASN.1 structure error = asn1DumpObject(p, n, 0); //Any error to report? if(error) break; //Parse X.509 certificate error = x509ParseCertificate(p, n, issuerCertInfo); //Failed to parse the X.509 certificate? if(error) break; //Validate current certificate error = x509ValidateCertificate(certInfo, issuerCertInfo); //Certificate validation failed? if(error) break; //Keep track of the issuer certificate memcpy(certInfo, issuerCertInfo, sizeof(X509CertificateInfo)); //Next certificate p += n; length -= n; } //Propagate exception if necessary... if(error) break; //Point to the first trusted CA certificate pemCert = context->trustedCaList; //Get the total length, in bytes, of the trusted CA list pemCertLength = context->trustedCaListLength; //DER encoded certificate derCert = NULL; derCertSize = 0; derCertLength = 0; //Loop through the list while(pemCertLength > 0) { //Decode PEM certificate error = pemReadCertificate(&pemCert, &pemCertLength, &derCert, &derCertSize, &derCertLength); //Any error to report? if(error) break; //Parse X.509 certificate error = x509ParseCertificate(derCert, derCertLength, issuerCertInfo); //Failed to parse the X.509 certificate? if(error) break; //Validate the certificate with the current trusted CA error = x509ValidateCertificate(certInfo, issuerCertInfo); //Certificate validation succeeded? if(!error) break; } //The certificate could not be matched with a known, trusted CA? if(error == ERROR_END_OF_FILE) error = ERROR_UNKNOWN_CA; //Free previously allocated memory osFreeMem(derCert); //End of exception handling block } while(0); //Free previously allocated memory osFreeMem(certInfo); osFreeMem(issuerCertInfo); //Clean up side effects if(error) { //Release previously allocated memory rsaFreePublicKey(&context->peerRsaPublicKey); dsaFreePublicKey(&context->peerDsaPublicKey); ecFreeDomainParameters(&context->peerEcParams); ecFree(&context->peerEcPublicKey); } //TLS operates as a client or a server? if(context->entity == TLS_CONNECTION_END_CLIENT) { //Update FSM state if(context->keyExchMethod != TLS_KEY_EXCH_RSA) context->state = TLS_STATE_SERVER_KEY_EXCHANGE; else context->state = TLS_STATE_CERTIFICATE_REQUEST; } else { //Prepare to receive ClientKeyExchange message... context->state = TLS_STATE_CLIENT_KEY_EXCHANGE; } //Return status code return error; }