/** * @brief * Load an EC public key from a file. * @param filename * the name of the file from which the key should be loaded * @return * a pointer to the deserialized public key from the the file. */ EC_KEY * _load_ec_pubkey(char const *filename) { char *filedata; unsigned char *bin; size_t binsize; EC_KEY *result; if (!filename) { RET_ERROR_PTR(ERR_BAD_PARAM, NULL); } if (!(filedata = _read_pem_data(filename, "PUBLIC KEY", 1))) { RET_ERROR_PTR(ERR_UNSPEC, "could not read ec pubkey pem file"); } bin = _b64decode(filedata, strlen(filedata), &binsize); _secure_wipe(filedata, strlen(filedata)); free(filedata); if (!bin) { RET_ERROR_PTR(ERR_UNSPEC, "could not decode b64 data"); } result = _deserialize_ec_pubkey(bin, binsize); _secure_wipe(bin, binsize); free(bin); if (!result) { RET_ERROR_PTR(ERR_UNSPEC, "could not deserialize binary ec pubkey"); } return result; }
/** * @brief Retrieves the encryption key from the keys file. * @param filename Null terminated filename string. * @return Pointer to the elliptic curve encryption key. * @free_using{free_ec_key} */ static EC_KEY *keys_fetch_enc_key(const char *filename) { size_t keys_len; unsigned char *keys_bin; EC_KEY *key; if(!filename) { RET_ERROR_PTR(ERR_BAD_PARAM, NULL); } else if(!strlen(filename)) { RET_ERROR_PTR(ERR_BAD_PARAM, NULL); } if(!(keys_bin = keys_file_serialize(filename, &keys_len))) { RET_ERROR_PTR(ERR_UNSPEC, "could not retrieve keys binary string"); } key = keys_serial_get_enc_key(keys_bin, keys_len); _secure_wipe(keys_bin, keys_len); free(keys_bin); if (!key) { RET_ERROR_PTR_FMT(ERR_UNSPEC, "could not retrieve ed25519 signing key from %s", filename); } return key; }
/** * @brief * Free an ed25519 keypair. * @param key * a pointer to the ed25519 keypair to be freed. */ void _free_ed25519_key(ED25519_KEY *key) { if (!key) { return; } _secure_wipe(key, sizeof(ED25519_KEY)); free(key); }
/** * @brief * Load an ed25519 private key from a file. * @param filename * the path of the armored file from which the ed25519 private key will be * loaded. * @return * a pointer to a newly allocated ed25519 keypair on success, or NULL on * failure. */ ED25519_KEY * _load_ed25519_privkey(char const *filename) { ED25519_KEY *result; unsigned char *keydata; char *pemdata; size_t klen; if (!filename) { RET_ERROR_PTR(ERR_BAD_PARAM, NULL); } if (!(pemdata = _read_pem_data(filename, "ED25519 PRIVATE KEY", 1))) { RET_ERROR_PTR(ERR_UNSPEC, "unable to read ed25519 private key data from PEM file"); } keydata = _b64decode(pemdata, strlen(pemdata), &klen); _secure_wipe(pemdata, strlen(pemdata)); free(pemdata); if (!keydata || (klen != ED25519_KEY_SIZE)) { if (keydata) { _secure_wipe(keydata, klen); free(keydata); } RET_ERROR_PTR(ERR_UNSPEC, "bad ED25519 key data was read from file"); } if (!(result = malloc(sizeof(ED25519_KEY)))) { PUSH_ERROR_SYSCALL("malloc"); _secure_wipe(keydata, klen); free(keydata); RET_ERROR_PTR(ERR_NOMEM, "unable to allocate space for ED25519 key"); } memset(result, 0, sizeof(ED25519_KEY)); memcpy(result->private_key, keydata, sizeof(result->private_key)); _secure_wipe(keydata, klen); free(keydata); ed25519_publickey_donna(result->private_key, result->public_key); return result; }
/** * @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; }
/** * @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; }
/** * @brief Creates a keys file with specified signing and encryption keys. * @param type Type of keys file, whether the keys correspond to a user or organizational signet. * @param sign_key Pointer to the specified ed25519 key, the private portion of which will be stored in the keys file as the signing key. * @param enc_key Pointer to the specified elliptic curve key, the private portion of which will be stored in the keys file as the encryption key. * @param filename Pointer to the NULL terminated string containing the filename for the keys file. * @return 0 on success, -1 on failure. */ static int keys_file_create(keys_type_t type, ED25519_KEY *sign_key, EC_KEY *enc_key, const char *filename) { char *b64_keys = NULL; int res; size_t serial_size = 0, enc_size = 0, at = 0;; unsigned char *serial_keys = NULL, *serial_enc = NULL, serial_sign[ED25519_KEY_SIZE], sign_fid, enc_fid; dime_number_t number; if(!sign_key || !enc_key || !filename) { RET_ERROR_INT(ERR_BAD_PARAM, NULL); } switch(type) { case KEYS_TYPE_ORG: number = DIME_ORG_KEYS; sign_fid = KEYS_ORG_PRIVATE_POK; enc_fid = KEYS_ORG_PRIVATE_ENC; break; case KEYS_TYPE_USER: number = DIME_USER_KEYS; sign_fid = KEYS_USER_PRIVATE_SIGN; enc_fid = KEYS_USER_PRIVATE_ENC; break; default: RET_ERROR_INT(ERR_BAD_PARAM, NULL); break; } memcpy(serial_sign, sign_key->private_key, ED25519_KEY_SIZE); if(!(serial_enc = _serialize_ec_privkey(enc_key, &enc_size))) { _secure_wipe(serial_sign, ED25519_KEY_SIZE); RET_ERROR_INT(ERR_UNSPEC, "could not serialize private key"); } serial_size = KEYS_HEADER_SIZE + 1 + 1 + ED25519_KEY_SIZE + 1 + 2 + enc_size; if(!(serial_keys = malloc(serial_size))) { PUSH_ERROR_SYSCALL("malloc"); _secure_wipe(serial_sign, ED25519_KEY_SIZE); _secure_wipe(serial_enc, enc_size); free(serial_enc); RET_ERROR_INT(ERR_NOMEM, NULL); } memset(serial_keys, 0, serial_size); _int_no_put_2b(serial_keys, (uint16_t)number); _int_no_put_3b(serial_keys + 2, (uint32_t)(serial_size - KEYS_HEADER_SIZE)); at = KEYS_HEADER_SIZE; serial_keys[at++] = sign_fid; serial_keys[at++] = ED25519_KEY_SIZE; memcpy(serial_keys + at, serial_sign, ED25519_KEY_SIZE); at += ED25519_KEY_SIZE; _secure_wipe(serial_sign, ED25519_KEY_SIZE); serial_keys[at++] = enc_fid; _int_no_put_2b(serial_keys + at, (uint16_t)enc_size); at += 2; memcpy(serial_keys + at, serial_enc, enc_size); _secure_wipe(serial_enc, enc_size); free(serial_enc); b64_keys = _b64encode(serial_keys, serial_size); _secure_wipe(serial_keys, serial_size); free(serial_keys); if (!b64_keys) { RET_ERROR_INT(ERR_UNSPEC, "could not base64 encode the keys"); } res = _write_pem_data(b64_keys, SIGNET_PRIVATE_KEYCHAIN, filename); _secure_wipe(b64_keys, strlen(b64_keys)); free(b64_keys); if(res < 0) { RET_ERROR_INT(ERR_UNSPEC, "could not store keys in PEM file."); } return 0; }