Beispiel #1
0
/**
 * @brief
 *  Deserialize an EC public key stored in binary format.
 * @param buf
 *  a pointer to the buffer holding the EC public key in binary format.
 * @param blen
 *  the length, in bytes, of the buffer holding the EC public key.
 * @return
 *  a pointer to the deserialized EC public key on success, or NULL on failure.
 */
EC_KEY * _deserialize_ec_pubkey(unsigned char const *buf, size_t blen) {
	EC_KEY *result;

	if (!buf || !blen) {
		RET_ERROR_PTR(ERR_BAD_PARAM, NULL);
	}

	if (!(result = EC_KEY_new_d())) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_PTR(ERR_UNSPEC, "could not generate new EC key for deserialization");
	}

	if (EC_KEY_set_group_d(result, EC_GROUP_new_by_curve_name_d(NID_secp256k1)) != 1) {
		PUSH_ERROR_OPENSSL();
		EC_KEY_free_d(result);
		RET_ERROR_PTR(ERR_UNSPEC, "could not get curve group for deserialization");
	}

	if (!(result = o2i_ECPublicKey_d(&result, (const unsigned char **)&buf, blen))) {
		PUSH_ERROR_OPENSSL();
		EC_KEY_free_d(result);
		RET_ERROR_PTR(ERR_UNSPEC, "deserialization of EC public key portion failed");
	}

	return result;
}
Beispiel #2
0
/**
 * @brief
 *  Sign a body of data using the ECDSA algorithm.
 * @param hash
 *  a pointer to the hashed data buffer to be signed.
 * @param hlen
 *  the length, in bytes, of the hashed data to be signed.
 * @param key
 *  the EC key which will have its private portion used to sign the supplied data.
 * @param siglen
 *  a pointer to a variable that will receive the length of the data signature
 *  buffer on success.
 * @return
 *  NULL on failure, or a pointer to the newly allocated signature data buffer
 *  on success.
 */
unsigned char * _ec_sign_data(unsigned char const *hash, size_t hlen, EC_KEY *key, size_t *siglen) {
	ECDSA_SIG *signature;
	unsigned char *buf = NULL;
	int bsize;

	if (!hash || !hlen || !key || !siglen) {
		RET_ERROR_PTR(ERR_BAD_PARAM, NULL);
	}

	if (!(signature = ECDSA_do_sign_d(hash, hlen, key))) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_PTR(ERR_UNSPEC, "unable to take ECDSA signature of hash buffer");
	}

	if ((bsize = i2d_ECDSA_SIG_d(signature, &buf)) < 0) {
		PUSH_ERROR_OPENSSL();
		ECDSA_SIG_free_d(signature);
		RET_ERROR_PTR(ERR_UNSPEC, "unable to serialize ECDSA signature");
	}

	ECDSA_SIG_free_d(signature);

	*siglen = bsize;

	return buf;
}
Beispiel #3
0
/**
 * @brief
 *  Serialize an EC public key to be shared.
 * @param
 *  key a pointer to the EC key pair to have its public key serialized.
 * @param
 *  outsize a pointer to a variable that will receive the length of the
 *  serialized key on success.
 * @return
 *  a pointer to the serialized EC public key on success, or NULL on failure.
 */
unsigned char * _serialize_ec_pubkey(EC_KEY *key, size_t *outsize) {
	unsigned char *buf = NULL;

	if (!key || !outsize) {
		RET_ERROR_PTR(ERR_BAD_PARAM, NULL);
	}

	stringer_t *pub;
	if (!(pub = secp256k1_public_get(key, MANAGEDBUF(33)))) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_PTR(ERR_UNSPEC, "unable to serialize EC public key");
	}

	buf = mm_alloc(33);
	memmove(buf, st_data_get(pub), st_length_get(pub));

	*outsize = st_length_get(pub);

//    EC_KEY_set_conv_form_d(key, POINT_CONVERSION_COMPRESSED);
//    if ((bsize = i2o_ECPublicKey_d(key, &buf)) < 0) {
//        PUSH_ERROR_OPENSSL();
//        RET_ERROR_PTR(ERR_UNSPEC, "unable to serialize EC public key");
//    }

//    *outsize = bsize;

	return buf;
}
Beispiel #4
0
/**
 * @brief
 *  Decrypt a data buffer using an AES-256 key (in CBC mode).
 * @param outbuf
 *  a pointer to the output buffer that will receive the decrypted data. NOTE:
 *  the size of this buffer must be successfully negotiated by the caller.
 * @param data
 *  a pointer to the data buffer to be decrypted.
 * @param dlen
 *  the size, in bytes, of the data buffer to be decrypted.
 * @param key
 *  a pointer to the 32-byte buffer holding the AES-256 decryption key for the
 *  operation.
 * @param iv
 *  a pointer to the 32-byte initialization vector to be used for the
 *  decryption process.
 * @return
 *  the number of bytes successfully decrypted on success, or -1 on failure.
 */
int _decrypt_aes_256(unsigned char *outbuf, unsigned char const *data, size_t dlen, unsigned char const *key, unsigned char const *iv) {
	EVP_CIPHER_CTX *ctx = NULL;
	int len, result;

	if (!outbuf || !data || !dlen || !key || !iv) {
		RET_ERROR_INT(ERR_BAD_PARAM, NULL);
	}

	if (dlen % AES_256_PADDING_SIZE) {
		RET_ERROR_INT(ERR_BAD_PARAM, "input data was not aligned to required padding size");
	}

	if (!(ctx = EVP_CIPHER_CTX_new_d())) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_INT(ERR_UNSPEC, "unable to create new context for AES-256 decryption");
	}

	if (EVP_DecryptInit_ex_d(ctx, EVP_aes_256_cbc_d(), NULL, key, iv) != 1) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_INT(ERR_UNSPEC, "unable to initialize context for AES-256 decryption");
	}

	if (EVP_CIPHER_CTX_set_padding_d(ctx, 0) != 1) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_INT(ERR_UNSPEC, "unable to set no padding for AES-256 decryption");
	}

	if (EVP_DecryptUpdate_d(ctx, outbuf, &len, data, dlen) != 1) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_INT(ERR_UNSPEC, "AES-256 decryption update failed");
	}

	result = len;

	if (EVP_DecryptFinal_ex_d(ctx, (unsigned char *)outbuf + len, &len) != 1) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_INT(ERR_UNSPEC, "AES-256 decryption finalization failed");
	}

	result += len;

	EVP_CIPHER_CTX_free_d(ctx);
	ctx = NULL;

	return result;
}
Beispiel #5
0
/**
 * @brief
 *  Initialize the cryptographic subsystem.
 * @return
 *  -1 if any part of the initialization process failed, or 0 on success.
 */
int _crypto_init(void) {
	SSL_load_error_strings_d();
	SSL_library_init_d();
	OPENSSL_add_all_algorithms_noconf_d();

	if (!(_encryption_group = EC_GROUP_new_by_curve_name_d(EC_ENCRYPT_CURVE))) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_INT(ERR_UNSPEC, "could not initialize encryption curve");
	}

	if (!(_ecies_envelope_evp = EVP_get_digestbyname_d(OBJ_nid2sn_d(NID_sha512)))) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_INT(ERR_UNSPEC, "unable to get SHA-512 digest by NID");
	}

	//EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_COMPRESSED);

	return 0;
}
Beispiel #6
0
/**
 * @brief
 *  Fill a buffer with a sequence of (securely) random bytes.
 * @param buf
 *  a pointer to the buffer to be filled with random bytes.
 * @param len
 *  the length, in bytes, of the buffer to be filled.
 * @return
 *  0 on success or -1 on failure.
 */
int _get_random_bytes(void *buf, size_t len) {
	if (!buf) {
		RET_ERROR_INT(ERR_BAD_PARAM, NULL);
	}

	if (!RAND_bytes_d(buf, len)) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_INT(ERR_UNSPEC, "unable to generate random bytes");
	}

	return 0;
}
Beispiel #7
0
/**
 * @brief
 *  Verify that an elliptic curve signature for a given hashed data buffer is
 *  valid.
 * @param hash
 *  a pointer to the hashed data buffer used to generate the signature.
 * @param hlen
 *  the length, in bytes, of the hashed data buffer.
 * @param sig
 *  a pointer to the signature buffer to be verified against the input data.
 * @param slen
 *  the length, in bytes, of the signature buffer.
 * @param key
 *  the EC key which will have its public portion used to verify the signature
 *  of the supplied hashed data.
 * @return
 *  -1 on general failure, 0 if the signature did not match the hashed data, or
 *  1 if it did.
 */
int _verify_ec_signature(unsigned char const *hash, size_t hlen, unsigned char const *sig, size_t slen, EC_KEY *key) {
	ECDSA_SIG *ec_sig;
	int result;

	if (!hash || !hlen || !sig || !slen || !key) {
		RET_ERROR_INT(ERR_BAD_PARAM, NULL);
	}

	if (!(ec_sig = d2i_ECDSA_SIG_d(NULL, &sig, slen))) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_INT(ERR_UNSPEC, "unable to read EC signature from buffer");
	}

	if ((result = ECDSA_do_verify_d(hash, hlen, ec_sig, key)) < 0) {
		PUSH_ERROR_OPENSSL();
		ECDSA_SIG_free_d(ec_sig);
		RET_ERROR_INT(ERR_UNSPEC, "unable to complete ECDSA signature verification");
	}

	ECDSA_SIG_free_d(ec_sig);

	return result;
}
Beispiel #8
0
END_TEST

START_TEST(test_openssl_error_100)
{
	ERR_clear_error();
	for (int i = 0; i < 100; i++) {
		ERR_put_error(ERR_LIB_SYS, SYS_F_FOPEN, ERR_R_SYS_LIB, "filename", 100 + i);
	}

	PUSH_ERROR_OPENSSL();

	const errinfo_t *last_error = get_last_error();
	ck_assert_ptr_ne(NULL, last_error);
	ck_assert_int_eq(ERR_OPENSSL, last_error->errcode);
	ck_assert_uint_eq(sizeof(last_error->auxmsg) - 1, strlen(last_error->auxmsg));
}
Beispiel #9
0
END_TEST

START_TEST(test_openssl_error_5)
{
	ERR_clear_error();
	for (int i = 0; i < 5; i++) {
		ERR_put_error(ERR_LIB_SYS, SYS_F_FOPEN, ERR_R_SYS_LIB, "filename", 100);
	}

	PUSH_ERROR_OPENSSL();

	const errinfo_t *last_error = get_last_error();
	ck_assert_ptr_ne(NULL, last_error);
	ck_assert_int_eq(ERR_OPENSSL, last_error->errcode);
	ck_assert_str_eq(ERRMSG SEP ERRMSG SEP ERRMSG SEP ERRMSG SEP ERRMSG, last_error->auxmsg);
}
Beispiel #10
0
/**
 * @brief
 *  Serialize an EC private key into a data buffer.
 * @param key
 *  a pointer to the EC key pair to have its private key serialized.
 * @param outsize
 *  a pointer to a variable that will receive the length of the serialized key
 *  on success.
 * @return
 *  a pointer to the serialized EC private key on success, or NULL on failure.
 */
unsigned char * _serialize_ec_privkey(EC_KEY *key, size_t *outsize) {
	unsigned char *buf = NULL;

	if (!key || !outsize) {
		RET_ERROR_PTR(ERR_BAD_PARAM, NULL);
	}

	stringer_t *priv;
	buf = mm_alloc(32);

	if (!(priv = secp256k1_private_get(key, PLACER(buf, 32)))) {
		//  if ((bsize = i2d_ECPrivateKey_d(key, &buf)) < 0) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_PTR(ERR_UNSPEC, "unable to serialize EC private key");
	}

	*outsize = 32;

	return buf;
}
Beispiel #11
0
/**
 * @brief
 *  Compute a derived AES-256 key from the intersection of a public EC key and
 *  a private EC key.
 */
int _compute_aes256_kek(EC_KEY *public_key, EC_KEY *private_key, unsigned char *keybuf) {
	unsigned char aeskey[SHA_512_SIZE];

	if (!public_key || !private_key || !keybuf) {
		RET_ERROR_INT(ERR_BAD_PARAM, NULL);
	}

	if (ECDH_compute_key_d(aeskey, sizeof(aeskey), EC_KEY_get0_public_key_d(public_key), private_key, _ecies_env_derivation) != SHA_512_SIZE) {
		PUSH_ERROR_OPENSSL();
		RET_ERROR_INT(ERR_UNSPEC, "could not derive AES key from EC keypair");
	}

	for (size_t i = 0; i < 16; ++i) {
		keybuf[i] = aeskey[i] ^ aeskey[i + 16];
	}

	memcpy(keybuf + 16, aeskey + 32, 32);
	_secure_wipe(aeskey, sizeof(aeskey));

	return 0;
}
Beispiel #12
0
END_TEST

/**
 * In an old version of the code that used strncat, this caused a SIGSEGV.
 */
START_TEST(test_openssl_error_longfilename)
{
	ERR_clear_error();
#define fn10   "1234567890"
#define fn50   fn10 fn10 fn10 fn10 fn10
#define fn250  fn50 fn50 fn50 fn50 fn50
#define fn1000 fn250 fn250 fn250 fn250
	ERR_put_error(ERR_LIB_SYS, SYS_F_FOPEN, ERR_R_SYS_LIB, fn1000, 1);
	ERR_put_error(ERR_LIB_SYS, SYS_F_FOPEN, ERR_R_SYS_LIB, fn1000, 1);

	PUSH_ERROR_OPENSSL();

	const errinfo_t *last_error = get_last_error();
	ck_assert_ptr_ne(NULL, last_error);
	ck_assert_int_eq(ERR_OPENSSL, last_error->errcode);
	ck_assert_uint_eq(sizeof(last_error->auxmsg) - 1, strlen(last_error->auxmsg));
}
Beispiel #13
0
/**
 * @brief
 *  Generate an ed25519 key pair.
 * @return
 *  a newly allocated and generated ed25519 key pair on success, or NULL on
 *  failure.
 */
ED25519_KEY * _generate_ed25519_keypair(void) {
	ED25519_KEY *result;

	if (!(result = malloc(sizeof(ED25519_KEY)))) {
		PUSH_ERROR_SYSCALL("malloc");
		RET_ERROR_PTR(ERR_NOMEM, "could not generate ed25519 key because of "
			"memory allocation error");
	}

	memset(result, 0, sizeof(ED25519_KEY));

	if (RAND_bytes_d(result->private_key, sizeof(result->private_key)) != 1) {
		PUSH_ERROR_OPENSSL();
		_secure_wipe(result, sizeof(ED25519_KEY));
		free(result);
		RET_ERROR_PTR(ERR_UNSPEC, "could not generate ed25519 secret key");
	}

	ed25519_publickey_donna(result->private_key, result->public_key);

	return result;
}