TlsContext *tlsInit(void) { TlsContext *context; //Allocate a memory buffer to hold the TLS context context = osAllocMem(sizeof(TlsContext)); //Failed to allocate memory if(!context) return NULL; //Clear TLS context memset(context, 0, sizeof(TlsContext)); //Reference to the underlying socket #if (TLS_BSD_SOCKET_SUPPORT == ENABLED) context->socket = -1; #else context->socket = NULL; #endif //Default operation mode context->entity = TLS_CONNECTION_END_CLIENT; //Default TLS version context->version = TLS_MIN_VERSION; //Default client authentication mode context->clientAuthMode = TLS_CLIENT_AUTH_NONE; //Initialize Diffie-Hellman context dhInit(&context->dhContext); //Initialize ECDH context ecdhInit(&context->ecdhContext); //Initialize peer's RSA public key rsaInitPublicKey(&context->peerRsaPublicKey); //Initialize peer's DSA public key dsaInitPublicKey(&context->peerDsaPublicKey); //Initialize peer's EC domain parameters ecInitDomainParameters(&context->peerEcParams); //Initialize peer's EC public key ecInit(&context->peerEcPublicKey); //Allocate send and receive buffers context->txBuffer = osAllocMem(TLS_TX_BUFFER_SIZE); context->rxBuffer = osAllocMem(TLS_RX_BUFFER_SIZE); //Failed to allocate memory? if(!context->txBuffer || !context->rxBuffer) { //Free previously allocated memory osFreeMem(context->txBuffer); osFreeMem(context->rxBuffer); osFreeMem(context); //Report an error return NULL; } //Clear send and receive buffers memset(context->txBuffer, 0, TLS_TX_BUFFER_SIZE); memset(context->rxBuffer, 0, TLS_RX_BUFFER_SIZE); //Return a handle to the freshly created TLS context return context; }
error_t udpDiscardStart(void) { error_t error; DiscardServiceContext *context; OsTask *task; //Debug message TRACE_INFO("Starting UDP discard service...\r\n"); //Allocate a memory block to hold the context context = osAllocMem(sizeof(DiscardServiceContext)); //Failed to allocate memory? if(!context) return ERROR_OUT_OF_MEMORY; //Start of exception handling block do { //Open a UDP socket context->socket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP); //Failed to open socket? if(!context->socket) { //Report an error error = ERROR_OPEN_FAILED; //Exit immediately break; } //The server listens for incoming datagrams on port 9 error = socketBind(context->socket, &IP_ADDR_ANY, DISCARD_PORT); //Unable to bind the socket to the desired port? if(error) break; //Create a task to handle incoming datagrams task = osCreateTask("UDP Discard", udpDiscardTask, context, DISCARD_SERVICE_STACK_SIZE, DISCARD_SERVICE_PRIORITY); //Unable to create the task? if(task == OS_INVALID_HANDLE) { //Report an error to the calling function error = ERROR_OUT_OF_RESOURCES; break; } //End of exception handling block } while(0); //Any error to report? if(error) { //Clean up side effects... socketClose(context->socket); osFreeMem(context); } //Return status code return error; }
error_t tlsSetServerName(TlsContext *context, const char_t *serverName) { size_t i; size_t length; //Invalid parameters? if(context == NULL || serverName == NULL) return ERROR_INVALID_PARAMETER; //Retrieve the length of the server name length = strlen(serverName); //Allocate a memory block to hold the hostname context->serverName = osAllocMem(length + 1); //Failed to allocate memory? if(!context->serverName) return ERROR_OUT_OF_MEMORY; //Convert the hostname into lowercase for(i = 0; i < length; i++) context->serverName[i] = tolower((uint8_t) serverName[i]); //Properly terminate the string with a NULL character context->serverName[length] = '\0'; //Successful processing return NO_ERROR; }
/************************************************************************************** * Function: AllocateBuffers * * Description: allocate all the memory needed for the MP3 decoder * * Inputs: none * * Outputs: none * * Return: pointer to MP3DecInfo structure (initialized with pointers to all * the internal buffers needed for decoding, all other members of * MP3DecInfo structure set to 0) * * Notes: if one or more mallocs fail, function frees any buffers already * allocated before returning **************************************************************************************/ MP3DecInfo *AllocateBuffers(void) { MP3DecInfo *mp3DecInfo; FrameHeader *fh; SideInfo *si; ScaleFactorInfo *sfi; HuffmanInfo *hi; DequantInfo *di; IMDCTInfo *mi; SubbandInfo *sbi; mp3DecInfo = (MP3DecInfo *)osAllocMem(sizeof(MP3DecInfo)); if (!mp3DecInfo) return 0; ClearBuffer(mp3DecInfo, sizeof(MP3DecInfo)); fh = (FrameHeader *) osAllocMem(sizeof(FrameHeader)); si = (SideInfo *) osAllocMem(sizeof(SideInfo)); sfi = (ScaleFactorInfo *) osAllocMem(sizeof(ScaleFactorInfo)); hi = (HuffmanInfo *) osAllocMem(sizeof(HuffmanInfo)); di = (DequantInfo *) osAllocMem(sizeof(DequantInfo)); mi = (IMDCTInfo *) osAllocMem(sizeof(IMDCTInfo)); sbi = (SubbandInfo *) osAllocMem(sizeof(SubbandInfo)); mp3DecInfo->FrameHeaderPS = (void *)fh; mp3DecInfo->SideInfoPS = (void *)si; mp3DecInfo->ScaleFactorInfoPS = (void *)sfi; mp3DecInfo->HuffmanInfoPS = (void *)hi; mp3DecInfo->DequantInfoPS = (void *)di; mp3DecInfo->IMDCTInfoPS = (void *)mi; mp3DecInfo->SubbandInfoPS = (void *)sbi; if (!fh || !si || !sfi || !hi || !di || !mi || !sbi) { FreeBuffers(mp3DecInfo); /* safe to call - only frees memory that was successfully allocated */ return 0; } /* important to do this - DSP primitives assume a bunch of state variables are 0 on first use */ ClearBuffer(fh, sizeof(FrameHeader)); ClearBuffer(si, sizeof(SideInfo)); ClearBuffer(sfi, sizeof(ScaleFactorInfo)); ClearBuffer(hi, sizeof(HuffmanInfo)); ClearBuffer(di, sizeof(DequantInfo)); ClearBuffer(mi, sizeof(IMDCTInfo)); ClearBuffer(sbi, sizeof(SubbandInfo)); return mp3DecInfo; }
error_t tlsParseChangeCipherSpec(TlsContext *context, const TlsChangeCipherSpec *message, size_t length) { error_t error; //Debug message TRACE_INFO("ChangeCipherSpec message received (%" PRIuSIZE " bytes)...\r\n", length); TRACE_DEBUG_ARRAY(" ", message, length); //Check the length of the ChangeCipherSpec message if(length < sizeof(TlsChangeCipherSpec)) 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_CHANGE_CIPHER_SPEC) return ERROR_UNEXPECTED_MESSAGE; } else { //Check current state if(context->state != TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC) return ERROR_UNEXPECTED_MESSAGE; } //Allocate a memory buffer to hold the decryption context context->readCipherContext = osAllocMem(context->cipherAlgo->contextSize); //Failed to allocate memory? if(!context->readCipherContext) return ERROR_OUT_OF_MEMORY; //Configure the decryption engine with the read key error = context->cipherAlgo->init(context->readCipherContext, context->readEncKey, context->encKeyLength); //Any error to report? if(error) return error; //Inform the record layer that subsequent records will be protected //under the newly negotiated encryption algorithm context->changeCipherSpecReceived = TRUE; //Prepare to receive a Finished message from the peer... context->state = (context->entity == TLS_CONNECTION_END_CLIENT) ? TLS_STATE_SERVER_FINISHED : TLS_STATE_CLIENT_FINISHED; //Successful processing return NO_ERROR; }
error_t tlsSendChangeCipherSpec(TlsContext *context) { error_t error; size_t length; TlsChangeCipherSpec *message; //Point to the ChangeCipherSpec message message = (TlsChangeCipherSpec *) (context->txBuffer + sizeof(TlsRecord)); //Write the type field message->type = 1; //The message consists of a single byte length = sizeof(TlsChangeCipherSpec); //Debug message TRACE_INFO("Sending ChangeCipherSpec message (%" PRIuSIZE " bytes)...\r\n", length); TRACE_DEBUG_ARRAY(" ", message, length); //Send ChangeCipherSpec message error = tlsWriteProtocolData(context, length, TLS_TYPE_CHANGE_CIPHER_SPEC); //Failed to send TLS record? if(error) return error; //Allocate a memory buffer to hold the encryption context context->writeCipherContext = osAllocMem(context->cipherAlgo->contextSize); //Failed to allocate memory? if(!context->writeCipherContext) return ERROR_OUT_OF_MEMORY; //Configure the encryption engine with the write key error = context->cipherAlgo->init(context->writeCipherContext, context->writeEncKey, context->encKeyLength); //Initialization failed? if(error) return error; //Inform the record layer that subsequent records will be protected //under the newly negotiated encryption algorithm context->changeCipherSpecSent = TRUE; //Prepare to send a Finished message to the peer... context->state = (context->entity == TLS_CONNECTION_END_CLIENT) ? TLS_STATE_CLIENT_FINISHED : TLS_STATE_SERVER_FINISHED; //Successful processing return NO_ERROR; }
error_t whirlpoolCompute(const void *data, size_t length, uint8_t *digest) { //Allocate a memory buffer to hold the Whirlpool context WhirlpoolContext *context = osAllocMem(sizeof(WhirlpoolContext)); //Failed to allocate memory? if(!context) return ERROR_OUT_OF_MEMORY; //Initialize the Whirlpool context whirlpoolInit(context); //Digest the message whirlpoolUpdate(context, data, length); //Finalize the Whirlpool message digest whirlpoolFinal(context, digest); //Free previously allocated memory osFreeMem(context); //Successful processing return NO_ERROR; }
error_t sha512_224Compute(const void *data, size_t length, uint8_t *digest) { //Allocate a memory buffer to hold the SHA-512/224 context Sha512_224Context *context = osAllocMem(sizeof(Sha512_224Context)); //Failed to allocate memory? if(!context) return ERROR_OUT_OF_MEMORY; //Initialize the SHA-512/224 context sha512_224Init(context); //Digest the message sha512_224Update(context, data, length); //Finalize the SHA-512/224 message digest sha512_224Final(context, digest); //Free previously allocated memory osFreeMem(context); //Successful processing return NO_ERROR; }
bool_t httpCheckPassword(HttpConnection *connection, const char_t *password, HttpAuthMode mode) { //This flag tells whether the password is valid bool_t status = FALSE; //Debug message TRACE_DEBUG("Password verification...\r\n"); #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED) //Basic authentication scheme? if(mode == HTTP_AUTH_MODE_BASIC) { //Point to the authentication credentials HttpAuthorizationHeader *auth = &connection->request.auth; //Make sure authentication credentials have been found if(auth->found && auth->mode == HTTP_AUTH_MODE_BASIC) { //Sanity check if(auth->password != NULL) { //Check whether the password is valid if(!strcmp(password, auth->password)) status = TRUE; } } } #endif #if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED) //Digest authentication scheme? if(mode == HTTP_AUTH_MODE_DIGEST) { //Point to the authentication credentials HttpAuthorizationHeader *auth = &connection->request.auth; //Make sure authentication credentials have been found if(auth->found && auth->mode == HTTP_AUTH_MODE_DIGEST) { //Sanity check if(auth->realm != NULL && auth->realm != NULL && auth->nonce != NULL && auth->qop != NULL && auth->nc != NULL && auth->cnonce != NULL && auth->response != NULL) { error_t error; Md5Context *md5Context; char_t ha1[2 * MD5_DIGEST_SIZE + 1]; char_t ha2[2 * MD5_DIGEST_SIZE + 1]; //Allocate a memory buffer to hold the MD5 context md5Context = osAllocMem(sizeof(Md5Context)); //MD5 context successfully allocated? if(md5Context != NULL) { //Compute HA1 = MD5(username : realm : password) md5Init(md5Context); md5Update(md5Context, auth->user, strlen(auth->user)); md5Update(md5Context, ":", 1); md5Update(md5Context, auth->realm, strlen(auth->realm)); md5Update(md5Context, ":", 1); md5Update(md5Context, password, strlen(password)); md5Final(md5Context, NULL); //Convert MD5 hash to hex string httpConvertArrayToHexString(md5Context->digest, MD5_DIGEST_SIZE, ha1); //Debug message TRACE_DEBUG(" HA1: %s\r\n", ha1); //Compute HA2 = MD5(method : uri) md5Init(md5Context); md5Update(md5Context, connection->request.method, strlen(connection->request.method)); md5Update(md5Context, ":", 1); md5Update(md5Context, auth->uri, strlen(auth->uri)); md5Final(md5Context, NULL); //Convert MD5 hash to hex string httpConvertArrayToHexString(md5Context->digest, MD5_DIGEST_SIZE, ha2); //Debug message TRACE_DEBUG(" HA2: %s\r\n", ha2); //Compute MD5(HA1 : nonce : nc : cnonce : qop : HA1) md5Init(md5Context); md5Update(md5Context, ha1, strlen(ha1)); md5Update(md5Context, ":", 1); md5Update(md5Context, auth->nonce, strlen(auth->nonce)); md5Update(md5Context, ":", 1); md5Update(md5Context, auth->nc, strlen(auth->nc)); md5Update(md5Context, ":", 1); md5Update(md5Context, auth->cnonce, strlen(auth->cnonce)); md5Update(md5Context, ":", 1); md5Update(md5Context, auth->qop, strlen(auth->qop)); md5Update(md5Context, ":", 1); md5Update(md5Context, ha2, strlen(ha2)); md5Final(md5Context, NULL); //Convert MD5 hash to hex string httpConvertArrayToHexString(md5Context->digest, MD5_DIGEST_SIZE, ha1); //Debug message TRACE_DEBUG(" response: %s\r\n", ha1); //Release MD5 context osFreeMem(md5Context); //Check response if(!strcasecmp(auth->response, ha1)) { //Perform nonce verification error = httpVerifyNonce(connection->serverContext, auth->nonce, auth->nc); //Valid nonce? if(!error) { //Access to the resource is granted status = TRUE; } else { //The client may wish to simply retry the request with a //new encrypted response, without re-prompting the user //for a new username and password connection->response.auth.stale = TRUE; } } } } } } #endif //Return TRUE is the password is valid, else FALSE return status; }
error_t ssiProcessIncludeCommand(HttpConnection *connection, const char_t *tag, size_t length, const char_t *uri, uint_t level) { error_t error; char_t *separator; char_t *attribute; char_t *value; char_t *path; char_t *p; //Discard invalid SSI directives if(length < 7 || length >= HTTP_SERVER_BUFFER_SIZE) return ERROR_INVALID_TAG; //Skip the SSI include command (7 bytes) memcpy(connection->buffer, tag + 7, length - 7); //Ensure the resulting string is NULL-terminated connection->buffer[length - 7] = '\0'; //Check whether a separator is present separator = strchr(connection->buffer, '='); //Separator not found? if(!separator) return ERROR_INVALID_TAG; //Split the tag *separator = '\0'; //Get attribute name and value attribute = strTrimWhitespace(connection->buffer); value = strTrimWhitespace(separator + 1); //Remove leading simple or double quote if(value[0] == '\'' || value[0] == '\"') value++; //Get the length of the attribute value length = strlen(value); //Remove trailing simple or double quote if(length > 0) { if(value[length - 1] == '\'' || value[length - 1] == '\"') value[length - 1] = '\0'; } //Check the length of the filename if(strlen(value) > HTTP_SERVER_URI_MAX_LEN) return ERROR_INVALID_TAG; //The file parameter defines the included file as relative to the document path if(!strcasecmp(attribute, "file")) { //Allocate a buffer to hold the path to the file to be included path = osAllocMem(strlen(uri) + strlen(value) + 1); //Failed to allocate memory? if(!path) return ERROR_OUT_OF_MEMORY; //Copy the path identifying the script file being processed strcpy(path, uri); //Search for the last slash character p = strrchr(path, '/'); //Remove the filename from the path if applicable if(p) strcpy(p + 1, value); else strcpy(path, value); } //The virtual parameter defines the included file as relative to the document root else if(!strcasecmp(attribute, "virtual")) { //Copy the absolute path path = strDuplicate(value); //Failed to duplicate the string? if(!path) return ERROR_OUT_OF_MEMORY; } //Unknown parameter... else { //Report an error return ERROR_INVALID_TAG; } //Use server-side scripting to dynamically generate HTML code? if(httpCompExtension(value, ".stm") || httpCompExtension(value, ".shtm") || httpCompExtension(value, ".shtml")) { //SSI processing (Server Side Includes) error = ssiExecuteScript(connection, path, level + 1); } else { #if (HTTP_SERVER_FS_SUPPORT == ENABLED) FsFile *file; //Retrieve the full pathname httpGetAbsolutePath(connection, path, connection->buffer, HTTP_SERVER_BUFFER_SIZE); //Open the file for reading file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ); //Successful operation? if(file) { //Send the contents of the requested file while(1) { //Read data from the specified file error = fsReadFile(file, connection->buffer, HTTP_SERVER_BUFFER_SIZE, &length); //End of input stream? if(error) break; //Send data to the client error = httpWriteStream(connection, connection->buffer, length); //Any error to report? if(error) break; } //Close the file fsCloseFile(file); //Successful file transfer? if(error == ERROR_END_OF_STREAM) error = NO_ERROR; } else { //The specified URI cannot be found error = ERROR_NOT_FOUND; } #else uint8_t *data; //Retrieve the full pathname httpGetAbsolutePath(connection, path, connection->buffer, HTTP_SERVER_BUFFER_SIZE); //Get the resource data associated with the file error = resGetData(connection->buffer, &data, &length); //Send the contents of the requested file if(!error) error = httpWriteStream(connection, data, length); #endif } //Cannot found the specified resource? if(error == ERROR_NOT_FOUND) error = ERROR_INVALID_TAG; //Release previously allocated memory osFreeMem(path); //return status code return error; }
OsTask *osCreateTask(const char_t *name, OsTaskCode taskCode, void *params, size_t stackSize, int_t priority) { OS_ERR err; CPU_INT32U i; CPU_STK stackLimit; OS_TCB *task; CPU_STK *stack; //The watermark limit is used to monitor and ensure that the stack does not overflow stackLimit = stackSize / 10; //Enter critical section osSuspendAllTasks(); //Loop through TCB table for(i = 0; i < OS_PORT_MAX_TASKS; i++) { //Check whether the current entry is free if(tcbTable[i] == NULL) break; } //Any entry available in the table? if(i < OS_PORT_MAX_TASKS) { //Allocate a memory block to hold the task's control block task = osAllocMem(sizeof(OS_TCB)); //Successful memory allocation? if(task != NULL) { //Allocate a memory block to hold the task's stack stack = osAllocMem(stackSize * sizeof(CPU_STK)); //Successful memory allocation? if(stack != NULL) { //Create a new task OSTaskCreate(task, (CPU_CHAR *) name, taskCode, params, priority, stack, stackLimit, stackSize, 0, 1, NULL, OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR, &err); //Check the return value if(err == OS_ERR_NONE) { //Save TCB base address tcbTable[i] = task; //Save stack base address stkTable[i] = stack; } else { //Clean up side effects osFreeMem(task); osFreeMem(stack); } } else { //Memory allocation failed err = OS_ERR_MEM_FULL; //Clean up side effects osFreeMem(task); } } else { //Memory allocation failed err = OS_ERR_MEM_FULL; } } else { //No entry available in the table err = OS_ERR_MEM_FULL; } //Leave critical section osResumeAllTasks(); //Check whether the task was successfully created if(err == OS_ERR_NONE) return task; else return NULL; }
error_t rsaesPkcs1v15Decrypt(const RsaPrivateKey *key, const uint8_t *ciphertext, size_t ciphertextLength, uint8_t *message, size_t messageSize, size_t *messageLength) { error_t error; uint_t i; uint_t k; uint8_t *em; Mpi c; Mpi m; //Check parameters if(key == NULL || ciphertext == NULL) return ERROR_INVALID_PARAMETER; if(message == NULL || messageLength == NULL) return ERROR_INVALID_PARAMETER; //Debug message TRACE_DEBUG("RSA PKCS #1 v1.5 decryption...\r\n"); TRACE_DEBUG(" Modulus:\r\n"); TRACE_DEBUG_MPI(" ", &key->n); TRACE_DEBUG(" Public exponent:\r\n"); TRACE_DEBUG_MPI(" ", &key->e); TRACE_DEBUG(" Private exponent:\r\n"); TRACE_DEBUG_MPI(" ", &key->d); TRACE_DEBUG(" Prime 1:\r\n"); TRACE_DEBUG_MPI(" ", &key->p); TRACE_DEBUG(" Prime 2:\r\n"); TRACE_DEBUG_MPI(" ", &key->q); TRACE_DEBUG(" Prime exponent 1:\r\n"); TRACE_DEBUG_MPI(" ", &key->dp); TRACE_DEBUG(" Prime exponent 2:\r\n"); TRACE_DEBUG_MPI(" ", &key->dq); TRACE_DEBUG(" Coefficient:\r\n"); TRACE_DEBUG_MPI(" ", &key->qinv); TRACE_DEBUG(" Ciphertext:\r\n"); TRACE_DEBUG_ARRAY(" ", ciphertext, ciphertextLength); //Initialize multiple-precision integers mpiInit(&c); mpiInit(&m); //Get the length in octets of the modulus n k = mpiGetByteLength(&key->n); //Check the length of the ciphertext if(ciphertextLength != k || ciphertextLength < 11) return ERROR_INVALID_LENGTH; //Allocate a buffer to store the encoded message EM em = osAllocMem(k); //Failed to allocate memory? if(!em) return ERROR_OUT_OF_MEMORY; //Start of exception handling block do { //Convert the ciphertext to an integer ciphertext representative c error = mpiReadRaw(&c, ciphertext, ciphertextLength); //Conversion failed? if(error) break; //Apply the RSADP decryption primitive error = rsadp(key, &c, &m); //Any error to report? if(error) break; //Convert the message representative m to an encoded message EM of length k octets error = mpiWriteRaw(&m, em, k); //Conversion failed? if(error) break; //Debug message TRACE_DEBUG(" Encoded message\r\n"); TRACE_DEBUG_ARRAY(" ", em, k); //The first octet of EM must have a value of 0x00 //and the block type BT shall be 0x02 if(em[0] != 0x00 || em[1] != 0x02) { //Report an error error = ERROR_UNEXPECTED_VALUE; break; } //An octet with hexadecimal value 0x00 is used to separate PS from M for(i = 2; i < k && em[i] != 0x00; i++); //Check whether the padding string is valid if(i < 10 || i >= k) { //Report an error error = ERROR_INVALID_PADDING; break; } //Ensure that the output buffer is large enough if(messageSize < (k - i - 1)) { //Report an error error = ERROR_INVALID_LENGTH; break; } //Recover the length of the message *messageLength = k - i - 1; //Copy the message contents memcpy(message, em + i + 1, *messageLength); //Debug message TRACE_DEBUG(" Message:\r\n"); TRACE_DEBUG_ARRAY(" ", message, *messageLength); //End of exception handling block } while(0); //Release multiple precision integers mpiFree(&c); mpiFree(&m); //Free previously allocated memory osFreeMem(em); //Return status code return error; }
error_t tlsAddCertificate(TlsContext *context, const char_t *certChain, size_t certChainLength, const char_t *privateKey, size_t privateKeyLength) { error_t error; const char_t *p; size_t n; uint8_t *derCert; size_t derCertSize; size_t derCertLength; X509CertificateInfo *certInfo; TlsCertificateType certType; TlsSignatureAlgo certSignAlgo; TlsHashAlgo certHashAlgo; TlsEcNamedCurve namedCurve; //Invalid TLS context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Check parameters if(certChain == NULL || certChainLength == 0) return ERROR_INVALID_PARAMETER; if(privateKey == NULL || privateKeyLength == 0) return ERROR_INVALID_PARAMETER; //Make sure there is enough room to add the certificate if(context->numCerts >= TLS_MAX_CERTIFICATES) return ERROR_OUT_OF_RESOURCES; //Allocate a memory buffer to store X.509 certificate info certInfo = osAllocMem(sizeof(X509CertificateInfo)); //Failed to allocate memory? if(!certInfo) return ERROR_OUT_OF_MEMORY; //Point to the beginning of the certificate chain p = certChain; n = certChainLength; //DER encoded certificate derCert = NULL; derCertSize = 0; derCertLength = 0; //Start of exception handling block do { //Decode end entity certificate error = pemReadCertificate(&p, &n, &derCert, &derCertSize, &derCertLength); //Any error to report? if(error) break; //Parse X.509 certificate error = x509ParseCertificate(derCert, derCertLength, certInfo); //Failed to parse the X.509 certificate? if(error) break; //Retrieve the signature algorithm that has been used to sign the certificate error = tlsGetCertificateType(certInfo, &certType, &certSignAlgo, &certHashAlgo, &namedCurve); //The specified signature algorithm is not supported? if(error) break; //End of exception handling block } while(0); //Check whether the certificate is acceptable if(!error) { //Point to the structure that describes the certificate TlsCertDesc *cert = &context->certs[context->numCerts]; //Save the certificate chain and the corresponding private key cert->certChain = certChain; cert->certChainLength = certChainLength; cert->privateKey = privateKey; cert->privateKeyLength = privateKeyLength; cert->type = certType; cert->signAlgo = certSignAlgo; cert->hashAlgo = certHashAlgo; cert->namedCurve = namedCurve; //Update the number of certificates context->numCerts++; } //Release previously allocated memory osFreeMem(derCert); osFreeMem(certInfo); //Return status code return error; }
error_t ping(NetInterface *interface, const IpAddr *ipAddr, size_t size, uint8_t ttl, systime_t timeout, systime_t *rtt) { error_t error; uint_t i; size_t length; uint16_t identifier; uint16_t sequenceNumber; systime_t startTime; systime_t roundTripTime; Socket *socket; IcmpEchoMessage *message; //Limit the size of the ping request size = MIN (size, PING_MAX_DATA_SIZE); //Debug message TRACE_INFO("Pinging %s with %u bytes of data...\r\n", ipAddrToString(ipAddr, NULL), size); //Length of the complete ICMP message including header and data length = sizeof(IcmpEchoMessage) + size; //Allocate memory buffer to hold an ICMP message message = osAllocMem(length); //Failed to allocate memory? if(!message) return ERROR_OUT_OF_MEMORY; //Identifier field is used to help matching requests and replies identifier = netGetRand(); //Sequence Number field is increment each time an Echo Request is sent sequenceNumber = osAtomicInc16(&pingSequenceNumber); //Format ICMP Echo Request message message->type = ICMP_TYPE_ECHO_REQUEST; message->code = 0; message->checksum = 0; message->identifier = identifier; message->sequenceNumber = sequenceNumber; //Copy data for(i = 0; i < size; i++) message->data[i] = i & 0xFF; #if (IPV4_SUPPORT == ENABLED) //Target address is an IPv4 address? if(ipAddr->length == sizeof(Ipv4Addr)) { Ipv4Addr srcIpAddr; //Select the source IPv4 address and the relevant network //interface to use when pinging the specified host error = ipv4SelectSourceAddr(&interface, ipAddr->ipv4Addr, &srcIpAddr); //Any error to report? if(error) { //Free previously allocated memory osFreeMem(message); //Return the corresponding error code return error; } //ICMP Echo Request message message->type = ICMP_TYPE_ECHO_REQUEST; //Message checksum calculation message->checksum = ipCalcChecksum(message, length); //Open a raw socket socket = socketOpen(SOCKET_TYPE_RAW_IP, SOCKET_IP_PROTO_ICMP); } else #endif #if (IPV6_SUPPORT == ENABLED) //Target address is an IPv6 address? if(ipAddr->length == sizeof(Ipv6Addr)) { Ipv6PseudoHeader pseudoHeader; //Select the source IPv6 address and the relevant network //interface to use when pinging the specified host error = ipv6SelectSourceAddr(&interface, &ipAddr->ipv6Addr, &pseudoHeader.srcAddr); //Any error to report? if(error) { //Free previously allocated memory osFreeMem(message); //Return the corresponding error code return error; } //ICMPv6 Echo Request message message->type = ICMPV6_TYPE_ECHO_REQUEST; //Format IPv6 pseudo header pseudoHeader.destAddr = ipAddr->ipv6Addr; pseudoHeader.length = htonl(length); pseudoHeader.reserved = 0; pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER; //Message checksum calculation message->checksum = ipCalcUpperLayerChecksum( &pseudoHeader, sizeof(Ipv6PseudoHeader), message, length); //Open a raw socket socket = socketOpen(SOCKET_TYPE_RAW_IP, SOCKET_IP_PROTO_ICMPV6); } else #endif //Target address is not valid? { //Free previously allocated memory osFreeMem(message); //Report an error return ERROR_INVALID_ADDRESS; } //Failed to open socket? if(!socket) { //Free previously allocated memory osFreeMem(message); //Report an error return ERROR_OPEN_FAILED; } //Set the TTL value to be used socket->ttl = ttl; //Associate the newly created socket with the relevant interface error = socketBindToInterface(socket, interface); //Unable to bind the socket to the desired interface? if(error) { //Free previously allocated memory osFreeMem(message); //Close socket socketClose(socket); //Return status code return error; } //Connect the socket to the target host error = socketConnect(socket, ipAddr, 0); //Any error to report? if(error) { //Free previously allocated memory osFreeMem(message); //Close socket socketClose(socket); //Return status code return error; } //Send Echo Request message error = socketSend(socket, message, length, NULL, 0); //Failed to send message ? if(error) { //Free previously allocated memory osFreeMem(message); //Close socket socketClose(socket); //Return status code return error; } //Save the time at which the request was sent startTime = osGetSystemTime(); //Timeout value exceeded? while((osGetSystemTime() - startTime) < timeout) { //Adjust receive timeout error = socketSetTimeout(socket, timeout); //Any error to report? if(error) break; //Wait for an incoming ICMP message error = socketReceive(socket, message, sizeof(IcmpEchoMessage) + size, &length, 0); //Any error to report? if(error) break; //Check message length if(length != (sizeof(IcmpEchoMessage) + size)) continue; //Verify message type if(ipAddr->length == sizeof(Ipv4Addr) && message->type != ICMP_TYPE_ECHO_REPLY) continue; if(ipAddr->length == sizeof(Ipv6Addr) && message->type != ICMPV6_TYPE_ECHO_REPLY) continue; //Response identifier matches request identifier? if(message->identifier != identifier) continue; //Make sure the sequence number is correct if(message->sequenceNumber != sequenceNumber) continue; //Loop through data field for(i = 0; i < size; i++) { //Compare received data against expected data if(message->data[i] != (i & 0xFF)) break; } //Valid Echo Reply message received? if(i == size) { //Calculate round-trip time roundTripTime = osGetSystemTime() - startTime; //Debug message TRACE_INFO("Echo received (round-trip time = %" PRIu32 " ms)...\r\n", roundTripTime); //Free previously allocated memory osFreeMem(message); //Close socket socketClose(socket); //Return round-trip time if(rtt != NULL) *rtt = roundTripTime; //No error to report return NO_ERROR; } } //Debug message TRACE_INFO("No echo received!\r\n"); //Free previously allocated memory osFreeMem(message); //Close socket socketClose(socket); //No Echo Reply received from host... return ERROR_NO_RESPONSE; }
error_t ssiExecuteScript(HttpConnection *connection, const char_t *uri, uint_t level) { error_t error; size_t length; #if (HTTP_SERVER_FS_SUPPORT == ENABLED) bool_t more; uint_t pos; uint_t n; char_t *buffer; FsFile *file; #else uint_t i; uint_t j; char_t *data; #endif //Recursion limit exceeded? if(level >= HTTP_SERVER_SSI_MAX_RECURSION) return NO_ERROR; //Retrieve the full pathname httpGetAbsolutePath(connection, uri, connection->buffer, HTTP_SERVER_BUFFER_SIZE); #if (HTTP_SERVER_FS_SUPPORT == ENABLED) //Open the file for reading file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ); //Failed to open the file? if(!file) return ERROR_NOT_FOUND; //Allocate a memory buffer buffer = osAllocMem(HTTP_SERVER_BUFFER_SIZE); //Failed to allocate memory? if(!buffer) { //Close the file fsCloseFile(file); //Report an error return ERROR_OUT_OF_MEMORY; } #else //Get the resource data associated with the URI error = resGetData(connection->buffer, (uint8_t **) &data, &length); //The specified URI cannot be found? if(error) return error; #endif //Send the HTTP response header before executing the script if(!level) { //Format HTTP response header connection->response.statusCode = 200; connection->response.contentType = mimeGetType(uri); connection->response.chunkedEncoding = TRUE; //Send the header to the client error = httpWriteHeader(connection); //Any error to report? if(error) { #if (HTTP_SERVER_FS_SUPPORT == ENABLED) //Close the file fsCloseFile(file); //Release memory buffer osFreeMem(buffer); #endif //Return status code return error; } } #if (HTTP_SERVER_FS_SUPPORT == ENABLED) //Point to the beginning of the buffer pos = 0; length = 0; //This flag indicates whether data should be read more = TRUE; //Parse the specified file while(1) { //Read more data if needed if(more) { //Read data from the specified file error = fsReadFile(file, buffer + pos + length, HTTP_SERVER_BUFFER_SIZE - (pos + length), &n); //End of input stream? if(error) { //Purge data buffer error = httpWriteStream(connection, buffer + pos, length); //Exit immediately break; } //Adjust the length of the buffer length += n; //Clear flag more = FALSE; } //Search for any SSI tags error = ssiSearchTag(buffer + pos, length, "<!--#", 5, &n); //Full match? if(error == NO_ERROR) { //Send the part of the file that precedes the tag error = httpWriteStream(connection, buffer + pos, n); //Failed to send data? if(error) break; //Advance data pointer pos += n; length -= n; //Search for the comment terminator error = ssiSearchTag(buffer + pos + 5, length - 5, "-->", 3, &n); //Full match? if(error == NO_ERROR) { //Advance data pointer over the opening identifier pos += 5; length -= 5; //Process SSI directive error = ssiProcessCommand(connection, buffer + pos, n, uri, level); //Any error to report? if(error) break; //Advance data pointer over the SSI tag pos += n + 3; length -= n + 3; } //No match or partial match? else { if(pos > 0) { //Move the remaining bytes to the start of the buffer memmove(buffer, buffer + pos, length); //Rewind to the beginning of the buffer pos = 0; //More data are needed more = TRUE; } else { //Send data to the client error = httpWriteStream(connection, buffer + pos, length); //Any error to report? if(error) break; //Rewind to the beginning of the buffer pos = 0; length = 0; //More data are needed more = TRUE; } } } //Partial match? else if(error == ERROR_PARTIAL_MATCH) { //Send the part of the file that precedes the tag error = httpWriteStream(connection, buffer + pos, n); //Failed to send data? if(error) break; //Advance data pointer pos += n; length -= n; //Move the remaining bytes to the start of the buffer memmove(buffer, buffer + pos, length); //Rewind to the beginning of the buffer pos = 0; //More data are needed more = TRUE; } //No match? else { //Send data to the client error = httpWriteStream(connection, buffer + pos, length); //Any error to report? if(error) break; //Rewind to the beginning of the buffer pos = 0; length = 0; //More data are needed more = TRUE; } } //Close the file fsCloseFile(file); //Release memory buffer osFreeMem(buffer); //Properly close the output stream if(!level && error == NO_ERROR) error = httpCloseStream(connection); #else //Parse the specified file while(length > 0) { //Search for any SSI tags error = ssiSearchTag(data, length, "<!--#", 5, &i); //Opening identifier found? if(!error) { //Search for the comment terminator error = ssiSearchTag(data + i + 5, length - i - 5, "-->", 3, &j); } //Check whether a valid SSI tag has been found? if(!error) { //Send the part of the file that precedes the tag error = httpWriteStream(connection, data, i); //Failed to send data? if(error) return error; //Advance data pointer over the opening identifier data += i + 5; length -= i + 5; //Process SSI directive error = ssiProcessCommand(connection, data, j, uri, level); //Any error to report? if(error) return error; //Advance data pointer over the SSI tag data += j + 3; length -= j + 3; } else { //Send the rest of the file error = httpWriteStream(connection, data, length); //Failed to send data? if(error) return error; //Advance data pointer data += length; length = 0; } } //Properly close the output stream if(!level) error = httpCloseStream(connection); #endif //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; }
void tcpEchoListenerTask(void *param) { error_t error; uint16_t clientPort; IpAddr clientIpAddr; Socket *serverSocket; Socket *clientSocket; EchoServiceContext *context; OsTask *task; //Point to the listening socket serverSocket = (Socket *) param; //Main loop while(1) { //Accept an incoming connection clientSocket = socketAccept(serverSocket, &clientIpAddr, &clientPort); //Check whether a valid connection request has been received if(!clientSocket) continue; //Debug message TRACE_INFO("Echo service: connection established with client %s port %" PRIu16 "\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort); //The socket operates in non-blocking mode error = socketSetTimeout(clientSocket, 0); //Any error to report? if(error) { //Close socket socketClose(clientSocket); //Wait for an incoming connection attempt continue; } //Allocate resources for the new connection context = osAllocMem(sizeof(EchoServiceContext)); //Failed to allocate memory? if(!context) { //Close socket socketClose(clientSocket); //Wait for an incoming connection attempt continue; } //Record the handle of the newly created socket context->socket = clientSocket; //Create a task to service the current connection task = osCreateTask("TCP Echo Connection", tcpEchoConnectionTask, context, ECHO_SERVICE_STACK_SIZE, ECHO_SERVICE_PRIORITY); //Did we encounter an error? if(task == OS_INVALID_HANDLE) { //Close socket socketClose(clientSocket); //Release resources osFreeMem(context); } } }
OsTask *osCreateTask(const char_t *name, OsTaskCode taskCode, void *params, size_t stackSize, int_t priority) { uint_t i; void *wa; OsTask *task = NULL; //Compute the size of the stack in bytes stackSize *= sizeof(uint_t); //Allocate a memory block to hold the working area wa = osAllocMem(THD_WA_SIZE(stackSize)); //Successful memory allocation? if(wa != NULL) { //Enter critical section chSysLock(); //Loop through task table for(i = 0; i < OS_PORT_MAX_TASKS; i++) { //Check whether the current entry is free if(taskTable[i].tp == NULL) break; } //Any entry available in the table? if(i < OS_PORT_MAX_TASKS) { //Create a new task taskTable[i].tp = chThdCreateI(wa, THD_WA_SIZE(stackSize), priority, (tfunc_t) taskCode, params); //Check whether the task was successfully created if(taskTable[i].tp != NULL) { //Insert the newly created task in the ready list chSchWakeupS(taskTable[i].tp, RDY_OK); //Save task pointer task = &taskTable[i]; //Save working area base address waTable[i] = wa; //Leave critical section chSysUnlock(); } else { //Leave critical section chSysUnlock(); //Clean up side effects osFreeMem(wa); } } else { //Leave critical section chSysUnlock(); //No entry available in the table osFreeMem(wa); } } //Return a pointer to the newly created task return task; }
error_t smtpSendMail(const SmtpAuthInfo *authInfo, const SmtpMail *mail) { error_t error; uint_t i; uint_t replyCode; IpAddr serverIpAddr; SmtpClientContext *context; //Check parameters if(!authInfo || !mail) return ERROR_INVALID_PARAMETER; //Make sure the server name is valid if(!authInfo->serverName) return ERROR_INVALID_PARAMETER; //Debug message TRACE_INFO("Sending a mail to %s port %" PRIu16 "...\r\n", authInfo->serverName, authInfo->serverPort); //The specified SMTP server can be either an IP or a host name error = getHostByName(authInfo->interface, authInfo->serverName, &serverIpAddr, 0); //Unable to resolve server name? if(error) return ERROR_NAME_RESOLUTION_FAILED; //Allocate a memory buffer to hold the SMTP client context context = osAllocMem(sizeof(SmtpClientContext)); //Failed to allocate memory? if(!context) return ERROR_OUT_OF_MEMORY; //Open a TCP socket context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); //Failed to open socket? if(!context->socket) { //Free previously allocated resources osFreeMem(context); //Report an error return ERROR_OPEN_FAILED; } #if (SMTP_TLS_SUPPORT == ENABLED) //Do not use SSL/TLS for the moment context->tlsContext = NULL; #endif //Start of exception handling block do { //Bind the socket to a particular network interface? if(authInfo->interface) { //Associate the socket with the relevant interface error = socketBindToInterface(context->socket, authInfo->interface); //Any error to report? if(error) break; } //Set timeout for blocking operations error = socketSetTimeout(context->socket, SMTP_DEFAULT_TIMEOUT); //Any error to report? if(error) break; //Connect to the SMTP server error = socketConnect(context->socket, &serverIpAddr, authInfo->serverPort); //Connection to server failed? if(error) break; #if (SMTP_TLS_SUPPORT == ENABLED) //Open a secure SSL/TLS session? if(authInfo->useTls) { //Initialize TLS context context->tlsContext = tlsInit(); //Initialization failed? if(!context->tlsContext) { //Unable to allocate memory error = ERROR_OUT_OF_MEMORY; //Stop immediately break; } //Bind TLS to the relevant socket error = tlsSetSocket(context->tlsContext, context->socket); //Any error to report? if(error) break; //Select client operation mode error = tlsSetConnectionEnd(context->tlsContext, TLS_CONNECTION_END_CLIENT); //Any error to report? if(error) break; //Set the PRNG algorithm to be used error = tlsSetPrng(context->tlsContext, authInfo->prngAlgo, authInfo->prngContext); //Any error to report? if(error) break; //Perform TLS handshake error = tlsConnect(context->tlsContext); //Failed to established a TLS session? if(error) break; } #endif //Wait for the connection greeting reply error = smtpSendCommand(context, NULL, &replyCode, NULL); //Any communication error to report? if(error) break; //Check whether the greeting message was properly received if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } //Clear security features context->authLoginSupported = FALSE; context->authPlainSupported = FALSE; context->authCramMd5Supported = FALSE; context->startTlsSupported = FALSE; //Send EHLO command and parse server response error = smtpSendCommand(context, "EHLO [127.0.0.1]\r\n", &replyCode, smtpEhloReplyCallback); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } #if (SMTP_TLS_SUPPORT == ENABLED) //Check whether the STARTTLS command is supported if(context->startTlsSupported && !context->tlsContext) { //Send STARTTLS command error = smtpSendCommand(context, "STARTTLS\r\n", &replyCode, NULL); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } //Initialize TLS context context->tlsContext = tlsInit(); //Initialization failed? if(!context->tlsContext) { //Unable to allocate memory error = ERROR_OUT_OF_MEMORY; //Stop immediately break; } //Bind TLS to the relevant socket error = tlsSetSocket(context->tlsContext, context->socket); //Any error to report? if(error) break; //Select client operation mode error = tlsSetConnectionEnd(context->tlsContext, TLS_CONNECTION_END_CLIENT); //Any error to report? if(error) break; //Set the PRNG algorithm to be used error = tlsSetPrng(context->tlsContext, authInfo->prngAlgo, authInfo->prngContext); //Any error to report? if(error) break; //Perform TLS handshake error = tlsConnect(context->tlsContext); //Failed to established a TLS session? if(error) break; //Clear security features context->authLoginSupported = FALSE; context->authPlainSupported = FALSE; context->authCramMd5Supported = FALSE; //Send EHLO command and parse server response error = smtpSendCommand(context, "EHLO [127.0.0.1]\r\n", &replyCode, smtpEhloReplyCallback); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } } #endif //Authentication requires a valid user name and password if(authInfo->userName && authInfo->password) { #if (SMTP_LOGIN_AUTH_SUPPORT == ENABLED) //LOGIN authentication mechanism supported? if(context->authLoginSupported) { //Perform LOGIN authentication error = smtpSendAuthLogin(context, authInfo); //Authentication failed? if(error) break; } else #endif #if (SMTP_PLAIN_AUTH_SUPPORT == ENABLED) //PLAIN authentication mechanism supported? if(context->authPlainSupported) { //Perform PLAIN authentication error = smtpSendAuthPlain(context, authInfo); //Authentication failed? if(error) break; } else #endif #if (SMTP_CRAM_MD5_AUTH_SUPPORT == ENABLED) //CRAM-MD5 authentication mechanism supported? if(context->authCramMd5Supported) { //Perform CRAM-MD5 authentication error = smtpSendAuthCramMd5(context, authInfo); //Authentication failed? if(error) break; } else #endif //No authentication mechanism supported? { //Skip authentication step } } //Format the MAIL FROM command (a null return path must be accepted) if(mail->from.addr) sprintf(context->buffer, "MAIL FROM:<%s>\r\n", mail->from.addr); else strcpy(context->buffer, "MAIL FROM:<>\r\n"); //Send the command to the server error = smtpSendCommand(context, context->buffer, &replyCode, NULL); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } //Format the RCPT TO command for(i = 0; i < mail->recipientCount; i++) { //Skip recipient addresses that are not valid if(!mail->recipients[i].addr) continue; //Format the RCPT TO command sprintf(context->buffer, "RCPT TO:<%s>\r\n", mail->recipients[i].addr); //Send the command to the server error = smtpSendCommand(context, context->buffer, &replyCode, NULL); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } } //Propagate exception if necessary if(error) break; //Send message body error = smtpSendData(context, mail); //Any error to report? if(error) break; //End of exception handling block } while(0); //Check status code if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE || error == ERROR_AUTHENTICATION_FAILED) { //Properly disconnect from the SMTP server smtpSendCommand(context, "QUIT\r\n", &replyCode, NULL); } #if (SMTP_TLS_SUPPORT == ENABLED) //Gracefully close SSL/TLS session if(context->tlsContext != NULL) tlsFree(context->tlsContext); #endif //Close socket socketClose(context->socket); //Clean up previously allocated resources osFreeMem(context); //Return status code return error; }
error_t rsassaPkcs1v15Verify(const RsaPublicKey *key, const HashAlgo *hash, const uint8_t *digest, const uint8_t *signature, size_t signatureLength) { error_t error; uint_t k; uint8_t *em; const uint8_t *oid; size_t oidLength; const uint8_t *d; size_t dLength; Mpi s; Mpi m; //Check parameters if(key == NULL || hash == NULL || digest == NULL || signature == NULL) return ERROR_INVALID_PARAMETER; //Debug message TRACE_DEBUG("RSA PKCS #1 v1.5 signature verification...\r\n"); TRACE_DEBUG(" Modulus:\r\n"); TRACE_DEBUG_MPI(" ", &key->n); TRACE_DEBUG(" Public exponent:\r\n"); TRACE_DEBUG_MPI(" ", &key->e); TRACE_DEBUG(" Message digest:\r\n"); TRACE_DEBUG_ARRAY(" ", digest, hash->digestSize); TRACE_DEBUG(" Signature:\r\n"); TRACE_DEBUG_ARRAY(" ", signature, signatureLength); //Initialize multiple-precision integers mpiInit(&s); mpiInit(&m); //Get the length in octets of the modulus n k = mpiGetByteLength(&key->n); //Check the length of the signature if(signatureLength != k) return ERROR_INVALID_LENGTH; //Allocate a memory buffer to hold the encoded message em = osAllocMem(k); //Failed to allocate memory? if(!em) return ERROR_OUT_OF_MEMORY; //Start of exception handling block do { //Convert the signature to an integer signature representative s error = mpiReadRaw(&s, signature, signatureLength); //Conversion failed? if(error) break; //Apply the RSAVP1 verification primitive error = rsavp1(key, &s, &m); //Any error to report? if(error) break; //Convert the message representative m to an encoded message EM of length k octets error = mpiWriteRaw(&m, em, k); //Conversion failed? if(error) break; //Debug message TRACE_DEBUG(" Encoded message\r\n"); TRACE_DEBUG_ARRAY(" ", em, k); //Parse the encoded message EM error = emsaPkcs1v15Decode(em, k, &oid, &oidLength, &d, &dLength); //Any error to report? if(error) break; //Assume an error... error = ERROR_INVALID_SIGNATURE_ALGO; //Ensure the hash algorithm identifier matches the OID if(oidComp(oid, oidLength, hash->oid, hash->oidSize)) break; //Check the length of the digest if(dLength != hash->digestSize) break; //Compare the message digest error = memcmp(digest, d, dLength) ? ERROR_INVALID_SIGNATURE : NO_ERROR; //End of exception handling block } while(0); //Release multiple precision integers mpiFree(&s); mpiFree(&m); //Free previously allocated memory osFreeMem(em); //Return status code return error; }
error_t httpServerProcessSetConfig(HttpConnection *connection) { error_t error; uint_t i; size_t n; char_t *p; char_t *buffer; char_t *separator; char_t *property; char_t *value; Settings *newSettings; //Point to the scratch buffer buffer = connection->buffer; //Allocate a memory buffer to hold the new configuration newSettings = osAllocMem(sizeof(Settings)); //Failed to allocate memory? if(!newSettings) return ERROR_OUT_OF_MEMORY; //Start of exception handling block do { //Retrieve default settings error = getDefaultSettings(newSettings); //Any error to report? if(error) break; //Process HTTP request body while(1) { //Read the HTTP request body until an ampersand is encountered error = httpReadStream(connection, buffer, HTTP_SERVER_BUFFER_SIZE - 1, &n, HTTP_FLAG_BREAK('&')); //End of stream detected? if(error) break; //Properly terminate the string with a NULL character buffer[n] = '\0'; //Remove the trailing ampersand if(n > 0 && buffer[n - 1] == '&') buffer[--n] = '\0'; //Decode the percent-encoded string error = httpDecodePercentEncodedString(buffer, buffer, HTTP_SERVER_BUFFER_SIZE); //Any error detected? if(error) break; //Check whether a separator is present separator = strchr(buffer, '='); //Separator found? if(separator) { //Split the line *separator = '\0'; //Get property name and value property = strTrimWhitespace(buffer); value = strTrimWhitespace(separator + 1); //Debug message TRACE_DEBUG("[%s]=%s\r\n", property, value); //Icecast settings if(!strcasecmp(property, "icecastSettingsUrl")) { //Check resource length if(strlen(value) >= sizeof(newSettings->icecast.url)) { //Report an error error = ERROR_INVALID_SYNTAX; break; } //Save resource strcpy(newSettings->icecast.url, value); } else if(!strcasecmp(property, "icecastSettingsPort")) { //Save Icecast server port newSettings->icecast.port = strtoul(value, &p, 10); //Invalid port number? if(*p != '\0') { //Report an error error = ERROR_INVALID_SYNTAX; break; } } //LAN settings else if(!strcasecmp(property, "lanSettingsMacAddr")) { //Save MAC address error = macStringToAddr(value, &newSettings->lan.macAddr); //Invalid address? if(error) break; } else if(!strcasecmp(property, "lanSettingsHostName")) { //Check the length of the host name if(strlen(value) >= sizeof(newSettings->lan.hostname)) { //Report an error error = ERROR_INVALID_SYNTAX; break; } //Save host name strcpy(newSettings->lan.hostname, value); } else if(!strcasecmp(property, "lanSettingsEnableDhcp")) { //Check flag value if(!strcasecmp(value, "off")) { //DHCP client is disabled newSettings->lan.enableDhcp = FALSE; } else if(!strcasecmp(value, "on")) { //DHCP client is enabled newSettings->lan.enableDhcp = TRUE; } else { //Invalid value error = ERROR_INVALID_SYNTAX; break; } } else if(!strcasecmp(property, "lanSettingsHostAddr")) { //Save IPv4 host address error = ipv4StringToAddr(value, &newSettings->lan.hostAddr); //Invalid address? if(error) break; } else if(!strcasecmp(property, "lanSettingsSubnetMask")) { //Save subnet mask error = ipv4StringToAddr(value, &newSettings->lan.subnetMask); //Invalid mask? if(error) break; } else if(!strcasecmp(property, "lanSettingsDefaultGateway")) { //Save default gateway error = ipv4StringToAddr(value, &newSettings->lan.defaultGateway); //Invalid address? if(error) break; } else if(!strcasecmp(property, "lanSettingsPrimaryDns")) { //Save primary DNS error = ipv4StringToAddr(value, &newSettings->lan.primaryDns); //Invalid address? if(error) break; } else if(!strcasecmp(property, "lanSettingsSecondaryDns")) { //Save secondary DNS error = ipv4StringToAddr(value, &newSettings->lan.secondaryDns); //Invalid address? if(error) break; } //Proxy settings else if(!strcasecmp(property, "proxySettingsEnable")) { //Check flag value if(!strcasecmp(value, "off")) { //Proxy server is disabled newSettings->proxy.enable = FALSE; } else if(!strcasecmp(value, "on")) { //Proxy server is enabled newSettings->proxy.enable = TRUE; } else { //Invalid value error = ERROR_INVALID_SYNTAX; break; } } else if(!strcasecmp(property, "proxySettingsName")) { //Check the length of proxy server name if(strlen(value) >= sizeof(newSettings->proxy.name)) { //Report an error error = ERROR_INVALID_SYNTAX; break; } //Save proxy server name strcpy(newSettings->proxy.name, value); } else if(!strcasecmp(property, "proxySettingsPort")) { //Save proxy server port newSettings->proxy.port = strtoul(value, &p, 10); //Invalid port number? if(*p != '\0') { //Report an error error = ERROR_INVALID_SYNTAX; break; } } } } //Check status code if(error == NO_ERROR || error == ERROR_END_OF_STREAM) { //Commit changes appSettings = *newSettings; //Write settings to non-volatile memory error = saveSettings(newSettings); } else if(error != ERROR_INVALID_SYNTAX) { //Propagate exception break; } //Point to the scratch buffer buffer = connection->buffer + 384; //Format XML data n = sprintf(buffer, "<data>\r\n <status>"); if(error == ERROR_INVALID_SYNTAX) n += sprintf(buffer + n, "Invalid configuration!\r\n"); else if(error != NO_ERROR) n += sprintf(buffer + n, "Failed to save settings to non-volatile memory!\r\n"); else n += sprintf(buffer + n, "Settings successfully saved. Please reboot the board.\r\n"); //Terminate XML data n += sprintf(buffer + n, "</status>\r\n</data>\r\n"); //Format HTTP response header connection->response.version = connection->request.version; connection->response.statusCode = 200; connection->response.keepAlive = connection->request.keepAlive; connection->response.noCache = TRUE; connection->response.contentType = mimeGetType(".xml"); connection->response.chunkedEncoding = FALSE; connection->response.contentLength = n; //Send the header to the client error = httpWriteHeader(connection); //Any error to report? if(error) break; //Send response body error = httpWriteStream(connection, buffer, n); //Any error to report? if(error) break; //Properly close output stream error = httpCloseStream(connection); //Any error to report? if(error) break; //End of exception handling block } while(0); //Free previously allocated memory osFreeMem(newSettings); //Return status code return error; }
OsTask *osCreateTask(const char_t *name, OsTaskCode taskCode, void *params, size_t stackSize, int_t priority) { uint_t i; OS_TASK *task; void *stack; //Enter critical section osSuspendAllTasks(); //Loop through TCB table for(i = 0; i < OS_PORT_MAX_TASKS; i++) { //Check whether the current entry is free if(tcbTable[i] == NULL) break; } //Any entry available in the table? if(i < OS_PORT_MAX_TASKS) { //Allocate a memory block to hold the task's control block task = osAllocMem(sizeof(OS_TASK)); //Successful memory allocation? if(task != NULL) { //Allocate a memory block to hold the task's stack stack = osAllocMem(stackSize * sizeof(uint_t)); //Successful memory allocation? if(stack != NULL) { //Create a new task OS_CreateTaskEx(task, name, priority, taskCode, stack, stackSize * sizeof(uint_t), 1, params); //Save TCB base address tcbTable[i] = task; //Save stack base address stkTable[i] = stack; } else { osFreeMem(task); //Memory allocation failed task = NULL; } } } else { //Memory allocation failed task = NULL; } //Leave critical section osResumeAllTasks(); //Return task pointer return task; }
error_t httpServerProcessGetConfig(HttpConnection *connection) { error_t error; uint_t i; size_t n; char_t *buffer; char_t temp[40]; //Allocate a memory buffer buffer = osAllocMem(2048); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Format XML data n = sprintf(buffer, "<settings>\r\n"); //Icecast settings n += sprintf(buffer + n, " <icecast>\r\n"); //Icecast resource n += sprintf(buffer + n, " <url>%s</url>\r\n", appSettings.icecast.url); //Icecast server port n += sprintf(buffer + n, " <port>%" PRIu16 "</port>\r\n", appSettings.icecast.port); //End of Icecast settings n += sprintf(buffer + n, " </icecast>\r\n"); //LAN settings n += sprintf(buffer + n, " <lan>\r\n"); //MAC address n += sprintf(buffer + n, " <macAddr>%s</macAddr>\r\n", macAddrToString(&appSettings.lan.macAddr, temp)); //Host name n += sprintf(buffer + n, " <hostName>%s</hostName>\r\n", appSettings.lan.hostname); //Enable DHCP n += sprintf(buffer + n, " <enableDhcp>%u</enableDhcp>\r\n", appSettings.lan.enableDhcp); //IPv4 host address n += sprintf(buffer + n, " <hostAddr>%s</hostAddr>\r\n", ipv4AddrToString(appSettings.lan.hostAddr, temp)); //Subnet mask n += sprintf(buffer + n, " <subnetMask>%s</subnetMask>\r\n", ipv4AddrToString(appSettings.lan.subnetMask, temp)); //Default gateway n += sprintf(buffer + n, " <defaultGateway>%s</defaultGateway>\r\n", ipv4AddrToString(appSettings.lan.defaultGateway, temp)); //Primary DNS n += sprintf(buffer + n, " <primaryDns>%s</primaryDns>\r\n", ipv4AddrToString(appSettings.lan.primaryDns, temp)); //Secondary DNS n += sprintf(buffer + n, " <secondaryDns>%s</secondaryDns>\r\n", ipv4AddrToString(appSettings.lan.secondaryDns, temp)); //End of LAN settings n += sprintf(buffer + n, " </lan>\r\n"); //Proxy settings n += sprintf(buffer + n, " <proxy>\r\n"); //Enable proxy server n += sprintf(buffer + n, " <enable>%u</enable>\r\n", appSettings.proxy.enable); //Proxy server name n += sprintf(buffer + n, " <name>%s</name>\r\n", appSettings.proxy.name); //Proxy server port n += sprintf(buffer + n, " <port>%" PRIu16 "</port>\r\n", appSettings.proxy.port); //End of proxy settings n += sprintf(buffer + n, " </proxy>\r\n"); //End of settings n += sprintf(buffer + n, "</settings>\r\n"); //Format HTTP response header connection->response.version = connection->request.version; connection->response.statusCode = 200; connection->response.keepAlive = connection->request.keepAlive; connection->response.noCache = TRUE; connection->response.contentType = mimeGetType(".xml"); connection->response.chunkedEncoding = FALSE; connection->response.contentLength = n; //Send the header to the client error = httpWriteHeader(connection); //Check status code if(!error) { //Send response body error = httpWriteStream(connection, buffer, n); } //Check status code if(!error) { //Properly close output stream error = httpCloseStream(connection); } //Free previously allocated memory osFreeMem(buffer); //Return status code return error; }