Exemplo n.º 1
0
/**
 * @brief	Print to a managed string and return the number of bytes written.
 * @see		vsnprintf()
 * @note	If the destination string pointer is NULL the function will simply return how much room would have been necessary.
 * @param	s		a pointer to the managed string that will receive the output of the print operation.
 * @param	format	a format string specifying the arguments of the print operation.
 * @param	args	a va_list containing the parameters to the print format string.
 * @return	-1 on failure, or the number of characters printed to the string, excluding the terminating null byte.
 */
size_t st_vsprint(stringer_t *s, chr_t *format, va_list args) {

	int_t length;
	size_t avail;
	uint32_t opts = *((uint32_t *)s);

#ifdef MAGMA_PEDANTIC
	if (!st_valid_destination(opts)) {
		log_pedantic("Invalid string options. { opt = %u = %s }", opts, st_info_opts(opts, MEMORYBUF(128), 128));
		return 0;
	}
#endif

	// If the target string is NULL, we just calculate how much room would be needed.
	if (!s) {
		length = vsnprintf(NULL, 0, format, args);
		return length;
	}

	// Print the provided format into the newly allocated buffer.
	length = vsnprintf(st_data_get(s), (avail = st_avail_get(s)), format, args);

#ifdef MAGMA_PEDANTIC
	if (length > avail) {
		log_pedantic("The output buffer was not large enough to hold the output, so the result was truncated.");
	}
#endif

	// If the length of the data segment is tracked explicitly, set the string length. Block strings assume the length of the buffer is the
	// the length of the data, and NULL strings don't explicitly track of their length so we skip this step for those string types.
	if (st_valid_tracked(opts)) {
		st_length_set(s, length > avail ? avail : length);
	}
	return length > avail ? avail : length;
}
Exemplo n.º 2
0
Arquivo: hex.c Projeto: lavabit/magma
/**
 * @brief	Convert a hex string into a binary data blob.
 * @note	All hex strings should be composed of pairs of two hex characters representing individual bytes.
 * 			Invalid hex characters will simply be ignored during processing.
 * @param	h		a managed string containing the input hex string to be decoded.
 * @param	output	if not NULL, a pointer to a managed string to contain the decoded binary output; if NULL, a new string
 * 					will be allocated and returned to the caller.
 * @return	a pointer to a managed string containing the decoded output, or NULL on failure.
 */
stringer_t * hex_decode_st(stringer_t *h, stringer_t *output) {

	uint32_t opts = 0;
	uchr_t *p = NULL, *o, c = 0;
	size_t w = 0, len = 0, valid;
	stringer_t *result = NULL;

	if (output && !st_valid_destination((opts = *((uint32_t *)output)))) {
		log_pedantic("An output string was supplied but it does not represent a buffer capable of holding the output.");
		return NULL;
	}
	else if (st_empty_out(h, &p, &len) || !(valid = hex_count_st(h))) {
		log_pedantic("The input block does not appear to hold any data ready for decoding. {%slen = %zu}", p ? "" : "p = NULL / ", len);
		return NULL;
	}

	// Make sure the output buffer is large enough or if output was passed in as NULL we'll attempt the allocation of our own buffer.
	if ((result = output) && ((st_valid_avail(opts) && st_avail_get(output) < (valid / 2)) ||
			(!st_valid_avail(opts) && st_length_get(output) < (valid / 2)))) {
		log_pedantic("The output buffer supplied is not large enough to hold the result. {avail = %zu / required = %zu}",
				st_valid_avail(opts) ? st_avail_get(output) : st_length_get(output), valid / 2);
		return NULL;
	}
	else if (!output && !(result = st_alloc(valid / 2))) {
		log_pedantic("The output buffer memory allocation request failed. {requested = %zu}", (valid / 2));
		return NULL;
	}

	// Store the memory address where the output should be written.
	o = st_data_get(result);

	// Loop through the input buffer and translate valid characters into a binary octet.
	for (size_t i = 0; i < len; i++) {
		if (hex_valid_chr(*p)) {
			if (!c) {
				c = *p;
			}
			else {
				*o++ = hex_decode_chr(c, *p);
				c = 0;
				w++;
			}
		}
		p++;
	}

	// If an output buffer was supplied that is capable of tracking the data length, or a managed string buffer was allocated update the length param.
	if (!output || st_valid_tracked(opts)) {
		st_length_set(result, w);
	}

	return result;
}
Exemplo n.º 3
0
Arquivo: hex.c Projeto: lavabit/magma
/**
 * @brief	Convert a block of binary data into a hex string.
 * @param	b		a managed string containing the raw data to be encoded.
 * @param	output	if not NULL, a pointer to a managed string that will store the encoded output; if NULL, a new managed string will
 * 					be allocated and returned to the caller.
 * @return 	NULL on failure, or a pointer to a managed string containing the hex-encoded output on success.
 */
stringer_t * hex_encode_st(stringer_t *b, stringer_t *output) {

	size_t len = 0;
	uint32_t opts = 0;
	uchr_t *p = NULL, *o;
	stringer_t *result = NULL;

	if (output && !st_valid_destination((opts = *((uint32_t *)output)))) {
		log_pedantic("An output string was supplied but it does not represent a buffer capable of holding the output.");
		return NULL;
	}
	else if (st_empty_out(b, &p, &len)) {
		log_pedantic("The input block does not appear to hold any data ready for encoding. {%slen = %zu}", p ? "" : "p = NULL / ", len);
		return NULL;
	}

	// Make sure the output buffer is large enough or if output was passed in as NULL we'll attempt the allocation of our own buffer.
	if ((result = output) && ((st_valid_avail(opts) && st_avail_get(output) < (len * 2)) ||
			(!st_valid_avail(opts) && st_length_get(output) < (len * 2)))) {
		log_pedantic("The output buffer supplied is not large enough to hold the result. {avail = %zu / required = %zu}",
				st_valid_avail(opts) ? st_avail_get(output) : st_length_get(output), len * 2);
		return NULL;
	}
	else if (!output && !(result = st_alloc(len * 2))) {
		log_pedantic("The output buffer memory allocation request failed. {requested = %zu}", len * 2);
		return NULL;
	}

	// Store the memory address where the output should be written.
	o = st_data_get(result);

	// Loop through the input buffer and write character pairs to the result string data buffer.
	for (size_t i = 0; i < len; i++) {
		hex_encode_chr(*p, o);
		o += 2;
		p += 1;
	}

	// If an output buffer was supplied that is capable of tracking the data length, or a managed string buffer was allocated update the length param.
	if (!output || st_valid_tracked(opts)) {
		st_length_set(result, len * 2);
	}

	return result;
}
Exemplo n.º 4
0
Arquivo: orgs.c Projeto: lavabit/magma
stringer_t * org_signet_get(prime_org_signet_t *org, stringer_t *output) {

	size_t length;
	int_t written = 0;
	stringer_t *result = NULL;

	if (!org || !(length = org_signet_length(org))) {
		log_pedantic("An invalid org signet was supplied for serialization.");
		return NULL;
	}

	// See if we have a valid output buffer, or if output is NULL, allocate a buffer to hold the output.
	else if (output && (!st_valid_destination(st_opt_get(output)) || st_avail_get(output) < length)) {
		log_pedantic("An output string was supplied but it does not represent a buffer capable of holding the output.");
		return NULL;
	}
	else if (!output && !(result = st_alloc(length))) {
		log_pedantic("Could not allocate a buffer large enough to hold encoded result. { requested = %zu }", length);
		return NULL;
	}
	else if (!output) {
		output = result;
	}

	st_wipe(output);

	// Calculate the size, by writing out all the fields (minus the header) using a NULL output.
	length = st_write(NULL, prime_field_write(PRIME_ORG_SIGNET, 1, ED25519_KEY_PUB_LEN, ed25519_public_get(org->signing, MANAGEDBUF(32)), MANAGEDBUF(34)),
		prime_field_write(PRIME_ORG_SIGNET, 3, SECP256K1_KEY_PUB_LEN, secp256k1_public_get(org->encryption, MANAGEDBUF(33)), MANAGEDBUF(35)),
		prime_field_write(PRIME_ORG_SIGNET, 4, ED25519_SIGNATURE_LEN, org->signature, MANAGEDBUF(65)));

	// Then output them again into the actual output buffer, but this time include the header. This is very primitive serialization logic.
	if ((written = st_write(output, prime_header_org_signet_write(length, MANAGEDBUF(5)),
		prime_field_write(PRIME_ORG_SIGNET, 1, ED25519_KEY_PUB_LEN, ed25519_public_get(org->signing, MANAGEDBUF(32)), MANAGEDBUF(34)),
		prime_field_write(PRIME_ORG_SIGNET, 3, SECP256K1_KEY_PUB_LEN, secp256k1_public_get(org->encryption, MANAGEDBUF(33)), MANAGEDBUF(35)),
		prime_field_write(PRIME_ORG_SIGNET, 4, ED25519_SIGNATURE_LEN, org->signature, MANAGEDBUF(65)))) != (length + 5)) {
		log_pedantic("The organizational signet didn't serialize to the expected length. { written = %i }", written);
		st_cleanup(result);
		return NULL;
	}

	return output;
}
Exemplo n.º 5
0
/**
 * @brief	Return a managed string containing sprintf()-style formatted data.
 * @param	opts	an options value to be passed to the allocation of the resulting managed string.
 * @param	format	a format string for the output string data.
 * @param	args	a variable argument list of parameters to be formatted as output.
 * @return	NULL on failure or a managed string containing the final formatted data on success.
 */
stringer_t * st_vaprint_opts(uint32_t opts, chr_t *format, va_list args) {

	void *out;
	va_list copy;
	int_t length, expected;
	stringer_t *result = NULL;

#ifdef MAGMA_PEDANTIC
	if (!st_valid_destination(opts)) {
		log_pedantic("Invalid string options. { opt = %u = %s }", opts, st_info_opts(opts, MEMORYBUF(128), 128));
		return NULL;
	}
#endif

	// Calculate the length.
	va_copy(copy, args);
	expected = length = vsnprintf(NULL, 0, format, copy);

	// Allocate a properly sized buffer.
	if (!length || !(result = st_alloc_opts(opts, length + 1)) || !(out = st_data_get(result))) {
		if (result) st_free(result);
		return NULL;
	}

	// Print the provided format into the newly allocated buffer.
	if ((length = vsnprintf(out, length + 1, format, args)) != expected) {
		log_pedantic("The print operation did not generate the amount of data we expected.");
		st_free(result);
		result = NULL;
	}

	if (st_valid_tracked(opts)) {
		st_length_set(result, length);
	}

	return result;
}
Exemplo n.º 6
0
Arquivo: hash.c Projeto: lavabit/magma
stringer_t * hash_digest(digest_t *digest, stringer_t *s, stringer_t *output) {

	int_t olen;
	uint_t rlen;
	uint32_t opts = 0;
	EVP_MD_CTX ctx;
	stringer_t *result = NULL;

	// Ensure a digest pointer was passed in and that we can retrieve the output length.
	if (!digest || (olen = EVP_MD_size_d((const EVP_MD *)digest)) <= 0) {
		log_pedantic("The hash algorithm is missing or invalid.");
		return NULL;
	}
	else if (output && !st_valid_destination((opts = *((uint32_t *)output)))) {
		log_pedantic("An output string was supplied but it does not represent a buffer capable of holding a result.");
		return NULL;
	}
	else if (st_empty(s)) {
		log_pedantic("The input string does not appear to have any data ready for encoding. {%slen = %zu}", s ? "" : "s = NULL / ",	s ? st_length_get(s) : 0);
		return NULL;
	}

	// Make sure the output buffer is large enough or if output was passed in as NULL we'll attempt the allocation of our own buffer.
	else if ((result = output) && ((st_valid_avail(opts) && st_avail_get(output) < olen) || (!st_valid_avail(opts) && st_length_get(output) < olen))) {
		log_pedantic("The output buffer supplied is not large enough to hold the result. {avail = %zu / required = %i}",
				st_valid_avail(opts) ? st_avail_get(output) : st_length_get(output), olen);
		return NULL;
	}
	else if (!output && !(result = st_alloc(olen))) {
		log_pedantic("The output buffer memory allocation request failed. {requested = %i}", olen);
		return NULL;
	}

	// Initialize the context.
	EVP_MD_CTX_init_d(&ctx);
	rlen = olen;

	// Setup the digest algorithm.
	if (EVP_DigestInit_ex_d(&ctx, (const EVP_MD *)digest, NULL) != 1) {
		log_pedantic("An error occurred while trying to initialize the hash context. {%s}",	ssl_error_string(MEMORYBUF(256), 256));
		EVP_MD_CTX_cleanup_d(&ctx);
		if (!output) {
			st_free(result);
		}
		return NULL;
	}

	// Process the input data.
	else if (EVP_DigestUpdate_d(&ctx, st_data_get(s), st_length_get(s)) != 1) {
		log_pedantic("An error occurred while trying to process the input data. {%s}", ssl_error_string(MEMORYBUF(256), 256));
		EVP_MD_CTX_cleanup_d(&ctx);
		if (!output) {
			st_free(result);
		}
		return NULL;
	}

	// Retrieve the hash output.
	else if (EVP_DigestFinal_d(&ctx, st_data_get(result), &rlen) != 1) {
		log_pedantic("An error occurred while trying to retrieve the hash result. {%s}", ssl_error_string(MEMORYBUF(256), 256));
		EVP_MD_CTX_cleanup_d(&ctx);
		if (!output) {
			st_free(result);
		}
		return NULL;
	}

	// Cleanup.
	EVP_MD_CTX_cleanup_d(&ctx);

	if (!output || st_valid_tracked(opts)) {
		st_length_set(result, rlen);
	}
	return result;
}