PKI_MEM *PKI_MEM_new_func ( void *obj, int (*func)(void *, unsigned char **p)) { size_t size = 0; int i = 0; PKI_MEM * ret = NULL; if (!obj || !func ) return NULL; if((i = func ( obj, NULL)) <= 0 ) { return NULL; } size = (size_t) i; if((ret = PKI_MEM_new ( size )) == NULL ) { return NULL; } if ( !func(obj, &(ret->data)) ) { PKI_MEM_free ( ret ); return NULL; } return ret; }
PKI_MEM * HSM_OPENSSL_sign(PKI_MEM *der, PKI_DIGEST_ALG *digest, PKI_X509_KEYPAIR *key) { EVP_MD_CTX *ctx = NULL; size_t out_size = 0; size_t ossl_ret = 0; PKI_MEM *out_mem = NULL; EVP_PKEY *pkey = NULL; if (!der || !der->data || !key || !key->value) { PKI_ERROR( PKI_ERR_PARAM_NULL, NULL); return NULL; } // Private Key pkey = key->value; // Get the Maximum size of a signature ossl_ret = out_size = (size_t) EVP_PKEY_size(pkey); // Initialize the return structure out_mem = PKI_MEM_new ((size_t)out_size); ctx = EVP_MD_CTX_new(); if (!out_mem || !ctx) { if (ctx) EVP_MD_CTX_free(ctx); if (out_mem) PKI_MEM_free(out_mem); PKI_ERROR( PKI_ERR_MEMORY_ALLOC, NULL); return NULL; } EVP_MD_CTX_init(ctx); EVP_SignInit_ex(ctx, digest, NULL); EVP_SignUpdate (ctx, der->data, der->size); // Finalize the signature if (!EVP_SignFinal(ctx, out_mem->data, (unsigned int *) &ossl_ret, pkey)) { PKI_log_err("ERROR while finalizing signature (%s)", HSM_OPENSSL_get_errdesc(HSM_OPENSSL_get_errno(), NULL, 0)); PKI_MEM_free(out_mem); out_mem = NULL; } else out_mem->size = (size_t) ossl_ret; // Cleanup the context #if OPENSSL_VERSION_NUMBER <= 0x1010000f EVP_MD_CTX_cleanup(ctx); #else EVP_MD_CTX_reset(ctx); #endif EVP_MD_CTX_free(ctx); return out_mem; }
PKI_MEM *PKI_MEM_new_data ( size_t size, unsigned char *data ) { PKI_MEM *ret = NULL; if( !data || size == 0 ) return ( NULL ); if((ret = PKI_MEM_new ( size )) == NULL ) { return ( NULL ); } memcpy(ret->data, data, size); return ( ret ); }
int PKI_HMAC_finalize(PKI_HMAC *hmac) { int size = 0; unsigned int verify_size = 0; if (!hmac || !hmac->initialized) return PKI_ERROR(PKI_ERR_PARAM_NULL, NULL); // Let's prepare the return value size = EVP_MD_size(hmac->digestAlg); verify_size = (unsigned int) size; // Generate a new PKI_MEM container hmac->value = PKI_MEM_new((size_t) size); // Let's finalize the HMAC #if OPENSSL_VERSION_NUMBER > 0x0090900fL int rv = HMAC_Final(&hmac->ctx, hmac->value->data, &verify_size); if (!rv) { PKI_log_err("can not finalize HMAC"); PKI_MEM_free(hmac->value); hmac->value = NULL; return PKI_ERR; } #else // In OpenSSL < 0.9.9 the return value is actually void HMAC_Final(&hmac->ctx, hmac->value->data, &verify_size); #endif // Checks the sizes if (verify_size != size) { PKI_log_err("Error while finalizing HMAC, size (%d) should be (%d)", verify_size, hmac->value->size); PKI_MEM_free(hmac->value); hmac->value = NULL; return PKI_ERR; } return PKI_OK; }
PKI_HTTP *PKI_HTTP_get_message (const PKI_SOCKET * sock, int timeout, size_t max_size) { PKI_HTTP * ret = NULL; char * eoh = NULL; char * body = NULL; ssize_t read = 0; // Keeps track of the single reading ssize_t free = 0; // Keeps track of the remaining buffer space ssize_t idx = 0; // Keeps track of how much data we poured into MEM ssize_t size = 0; // Keeps track of the read data from socket // Let's initialize some useful variables (code readability) long long content_length = -1; // Buffer where to keep the data PKI_MEM *m = NULL; // Allocates the HTTP message container if ((ret = PKI_HTTP_new()) == NULL) { PKI_ERROR(PKI_ERR_MEMORY_ALLOC, NULL ); goto err; } ret->method = PKI_HTTP_METHOD_UNKNOWN; if (max_size > 0) { // Allocates a new MEM object m = PKI_MEM_new(max_size + 1); } else { // Allocates the default buffer for HTTP messages m = PKI_MEM_new(HTTP_BUF_SIZE + 1); } if (m == NULL) { PKI_ERROR(PKI_ERR_MEMORY_ALLOC, NULL); return NULL; } // Sets the free space in the buffer free = (ssize_t) m->size - 1; // Let's retrieve the data from the socket. Note that this for // always read at most 'free' bytes which carries the amount of // free space in the buffer -> safe for (read = PKI_SOCKET_read(sock, (char *)(&(m->data[idx])), (size_t) free, timeout); read > 0; read = PKI_SOCKET_read(sock, (char *)(&(m->data[idx])), (size_t) free, timeout)) { // If read is negative, there was an error on the socket // let's just report it as an error and move on if (read < 0) { if (!eoh) { PKI_log_err("Error while reading from socket"); goto err; } else { // Nothing to read anymore - let's break PKI_log_err("Nothing to read anymore (read = %d)", read); break; } } else if (read == 0 && eoh) { // No data was read, let's assume the stream is complete and // break from the for loop break; } // Let's be sure there is a NULL-bound limit to the read data size += read; free -= read; m->data[size] = '\x0'; // If we don't have a header yet, let's look for it if (!eoh && ((eoh = __find_end_of_header(m, idx)) != NULL)) { // We want the header to finish with just one '\r\n' - since the // pointer we receive is at the end of the '\r\n\r\n' sequence, // we need to shrink by 2 bytes size_t header_size = (size_t) (eoh - (char *) m->data - 2); ret->head = PKI_MEM_new_data(header_size + 1, m->data); ret->head->data[header_size] = '\x0'; // If we can not parse the header - we have to return error if (PKI_ERR == __parse_http_header(ret)) goto err; // Let's get the pointer to the start of the body body = eoh + 1; // Checks for the content-length is in the header - if we have not found it, yet if (ret->method != PKI_HTTP_METHOD_GET && content_length < 0) { char *cnt_len_s = NULL; if ((cnt_len_s = PKI_HTTP_get_header(ret, "Content-Length" )) != NULL) { content_length = atoll(cnt_len_s); PKI_Free(cnt_len_s); // PKI_log_debug ( "HTTP Content-Length: %d bytes", content_length); } } } // End of if (!eoh) ... // Updates the start pointer for the next read operation idx += read; // Let's check if we need to expand the buffer if (max_size <= 0) { // We expand the mem if the buffer has less than 2K free if (free < 2048) { ssize_t ofs = 0; if(body) { ofs = (ssize_t)(body - (char *)m->data); if(ofs < 0) { PKI_log_debug ( "Invalid offset for HTTP body: Start: %p - Body: %p", m->data, body); PKI_ERROR(PKI_ERR_URI_READ, NULL); goto err; } } // Grow the memory for the HTTP message if(content_length > 0 && body && m->size < (size_t)(content_length + ofs)) { size_t len = ((size_t)(content_length + ofs) - m->size); if (PKI_MEM_grow(m, len + 1) == PKI_ERR) { PKI_ERROR(PKI_ERR_MEMORY_ALLOC, NULL); goto err; } free += (ssize_t)len; } else { if (PKI_MEM_grow(m, HTTP_BUF_SIZE) == PKI_ERR) { PKI_ERROR(PKI_ERR_MEMORY_ALLOC, NULL); goto err; } free += HTTP_BUF_SIZE; } // Let's update the pointer to the body if(body) body = (char *)m->data + ofs; } } // Let's check if we need to perform the next read or not if (eoh && ret->method == PKI_HTTP_METHOD_GET) { // We do not need to wait for any other read as GETs do not have // a full body break; } else if ((content_length >= 0) && (&m->data[size] - (unsigned char *)body >= content_length)) { // Here we have received the full body (since the size of the body corresponds or exceeds the // contents of the Content-Length: header line), therefore we can safely get out of the cycle break; } } /* End of for..loop */ // Here we should have both the eoh and the body - if not, there was // an error and we return the malformed request message if (!eoh) { // PKI_log_err ( "Read data (so far): %d bytes - Last read: %d bytes", idx, read); PKI_ERROR(PKI_ERR_URI_READ, NULL); goto err; } // Sets some HTTP specific data ret->location = PKI_HTTP_get_header ( ret, "Location" ); ret->type = PKI_HTTP_get_header ( ret, "Content-Type" ); if (ret->method != PKI_HTTP_METHOD_GET && content_length > 0 && body) { ssize_t body_start = (ssize_t)(body - (char *)m->data); ssize_t body_size = idx - body_start; if (body_start < 0 || body_size < 0) { PKI_log_err ( "Invalid offset for HTTP body - body_start: %d bytes - body_size: %d bytes", body_start, body_size); PKI_ERROR(PKI_ERR_URI_READ, NULL); goto err; } //Check if Content-Length > 0 but body_size is 0 if (body_size == 0) goto err; // Let's allocate the body for the HTTP message (if any) ret->body = PKI_MEM_new_data((size_t)body_size+1, (unsigned char *)body); if(ret->body == NULL) { PKI_ERROR(PKI_ERR_MEMORY_ALLOC, NULL); goto err; } ret->body->size = (size_t) body_size; } else { ret->body = PKI_MEM_new_null(); } // Let's free the buffer memory if (m) PKI_MEM_free(m); // Now we can return the HTTP message return ret; err: // First we free the return message if (ret) PKI_HTTP_free(ret); // We then free the buffer memory object if (m) PKI_MEM_free(m); return NULL; }