error_t tlsShutdown(TlsContext *context) { error_t error; //Invalid TLS context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Check current state if(context->state == TLS_STATE_APPLICATION_DATA || context->state == TLS_STATE_CLOSED) { //Notifies the recipient that the sender will not send //any more messages on this connection error = tlsSendAlert(context, TLS_ALERT_LEVEL_WARNING, TLS_ALERT_CLOSE_NOTIFY); //Update FSM state context->state = TLS_STATE_CLOSED; } else { //Report an error error = ERROR_NOT_CONNECTED; } //Return status code return error; }
error_t tlsSendCertificate(TlsContext *context) { error_t error; bool_t sendCert; uint8_t *p; size_t length; const char_t *pemCert; size_t pemCertLength; uint8_t *derCert; size_t derCertSize; size_t derCertLength; TlsCertificate *message; //TLS operates as a client or a server? if(context->entity == TLS_CONNECTION_END_CLIENT) { //The client must send a Certificate message if the server requests it sendCert = context->clientCertRequested ? TRUE : FALSE; #if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= SSL_VERSION_3_0) //SSL 3.0 currently selected? if(context->version == SSL_VERSION_3_0) { //The server requests a certificate but no suitable certificate is available? if(sendCert && context->cert == NULL) { //The client should send a no_certificate alert instead error = tlsSendAlert(context, TLS_ALERT_LEVEL_WARNING, TLS_ALERT_NO_CERTIFICATE); //Any error to report? if(error) return error; //Skip Certificate message... sendCert = FALSE; } } #endif } else { //The server must send a Certificate message whenever the agreed-upon //key exchange method uses certificates for authentication sendCert = (context->cert != NULL) ? TRUE : FALSE; } //Check whether a Certificate message must be sent if(sendCert) { //Buffer where to format the message p = context->txBuffer + sizeof(TlsRecord); //Point to the Certificate message message = (TlsCertificate *) p; //Format message header message->msgType = TLS_TYPE_CERTIFICATE; //Point to the first certificate of the list p = message->certificateList; //Length of the certificate list in bytes length = 0; //Check whether a certificate is available if(context->cert != NULL) { //Point to the certificate chain pemCert = context->cert->certChain; //Get the total length, in bytes, of the certificate chain pemCertLength = context->cert->certChainLength; } else { //If no suitable certificate is available, the message //contains an empty certificate list pemCert = NULL; pemCertLength = 0; } //DER encoded certificate derCert = NULL; derCertSize = 0; derCertLength = 0; //Parse the certificate chain while(pemCertLength > 0) { //Decode PEM certificate error = pemReadCertificate(&pemCert, &pemCertLength, &derCert, &derCertSize, &derCertLength); //Any error to report? if(error) break; //Total length of the certificate list length += derCertLength + 3; //Prevent the buffer from overflowing if((length + sizeof(TlsCertificate)) > TLS_MAX_PROTOCOL_DATA_LENGTH) return ERROR_MESSAGE_TOO_LONG; //Each certificate is preceded by a 3-byte length field STORE24BE(derCertLength, p); //Copy the current certificate memcpy(p + 3, derCert, derCertLength); //Advance data pointer p += derCertLength + 3; } //Free previously allocated memory osFreeMem(derCert); //A 3-byte length field shall precede the certificate list STORE24BE(length, message->certificateListLength); //Consider the 3-byte length field length += 3; //Fix message header STORE24BE(length, message->length); //Length of the complete handshake message length += sizeof(TlsHandshake); //Debug message TRACE_INFO("Sending Certificate message (%" PRIuSIZE " bytes)...\r\n", length); TRACE_DEBUG_ARRAY(" ", message, length); //Send handshake message error = tlsWriteProtocolData(context, length, TLS_TYPE_HANDSHAKE); //Failed to send TLS record? if(error) return error; } //Update FSM state context->state = (context->entity == TLS_CONNECTION_END_CLIENT) ? TLS_STATE_CLIENT_KEY_EXCHANGE : TLS_STATE_SERVER_KEY_EXCHANGE; //Successful processing return NO_ERROR; }