Advanced Linux Security and Cryptography Programming: Building Secure Systems and Encryption Frameworks
Advanced Linux security programming requires comprehensive understanding of cryptographic principles, secure coding practices, and system-level security mechanisms. This guide explores building robust security frameworks, implementing custom cryptographic solutions, and developing applications that meet the highest security standards for enterprise and government environments.
Advanced Linux Security and Cryptography Programming
Comprehensive Cryptographic Framework
Advanced Encryption and Key Management System
// crypto_framework.c - Advanced cryptographic framework
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/random.h>
#include <time.h>
#include <pthread.h>
#include <signal.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/rsa.h>
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/rand.h>
#include <openssl/kdf.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/pkcs12.h>
#include <openssl/err.h>
#define MAX_KEY_SIZE 4096
#define MAX_BLOCK_SIZE 64
#define MAX_IV_SIZE 16
#define MAX_TAG_SIZE 16
#define MAX_SALT_SIZE 32
#define MAX_KEYS 1000
#define SECURE_MEMORY_SIZE (1024 * 1024) // 1MB secure memory pool
// Encryption algorithms
typedef enum {
CRYPTO_AES_128_GCM,
CRYPTO_AES_256_GCM,
CRYPTO_AES_128_CBC,
CRYPTO_AES_256_CBC,
CRYPTO_CHACHA20_POLY1305,
CRYPTO_RSA_2048,
CRYPTO_RSA_4096,
CRYPTO_ECDSA_P256,
CRYPTO_ECDSA_P384,
CRYPTO_ECDSA_P521,
CRYPTO_ECDH_P256,
CRYPTO_ECDH_P384
} crypto_algorithm_t;
// Key types
typedef enum {
KEY_TYPE_SYMMETRIC,
KEY_TYPE_RSA_PRIVATE,
KEY_TYPE_RSA_PUBLIC,
KEY_TYPE_EC_PRIVATE,
KEY_TYPE_EC_PUBLIC
} key_type_t;
// Secure key structure
typedef struct {
uint32_t key_id;
key_type_t type;
crypto_algorithm_t algorithm;
size_t key_size;
uint8_t *key_data;
time_t creation_time;
time_t expiration_time;
uint32_t usage_count;
uint32_t max_usage;
bool revoked;
pthread_mutex_t lock;
} secure_key_t;
// Cryptographic context
typedef struct {
EVP_PKEY *private_key;
EVP_PKEY *public_key;
X509 *certificate;
crypto_algorithm_t algorithm;
uint8_t *session_key;
size_t session_key_size;
uint8_t iv[MAX_IV_SIZE];
uint8_t tag[MAX_TAG_SIZE];
size_t tag_size;
} crypto_context_t;
// Secure memory pool
typedef struct {
void *memory_pool;
size_t pool_size;
size_t allocated;
bool *allocation_map;
size_t block_size;
pthread_mutex_t pool_lock;
} secure_memory_pool_t;
// Key management system
typedef struct {
secure_key_t *keys[MAX_KEYS];
uint32_t next_key_id;
pthread_rwlock_t keys_lock;
// Hardware security module interface
struct {
bool available;
void *handle;
int (*init)(void);
int (*generate_key)(crypto_algorithm_t alg, uint8_t **key, size_t *key_size);
int (*encrypt)(const uint8_t *key, size_t key_size, const uint8_t *plain,
size_t plain_size, uint8_t **cipher, size_t *cipher_size);
int (*decrypt)(const uint8_t *key, size_t key_size, const uint8_t *cipher,
size_t cipher_size, uint8_t **plain, size_t *plain_size);
void (*cleanup)(void);
} hsm;
// Secure random number generator
struct {
bool initialized;
pthread_mutex_t rng_lock;
SHA256_CTX entropy_ctx;
uint8_t entropy_pool[256];
size_t entropy_count;
} rng;
secure_memory_pool_t secure_memory;
} key_management_system_t;
static key_management_system_t kms = {0};
// Function prototypes
static int init_crypto_framework(void);
static void cleanup_crypto_framework(void);
static int init_secure_memory_pool(void);
static void cleanup_secure_memory_pool(void);
static void *secure_malloc(size_t size);
static void secure_free(void *ptr, size_t size);
static int secure_random_bytes(uint8_t *buffer, size_t size);
static int init_hardware_rng(void);
// Secure memory management
static int init_secure_memory_pool(void)
{
kms.secure_memory.pool_size = SECURE_MEMORY_SIZE;
kms.secure_memory.block_size = 64; // 64-byte blocks
size_t num_blocks = kms.secure_memory.pool_size / kms.secure_memory.block_size;
// Allocate secure memory using mlock
kms.secure_memory.memory_pool = mmap(NULL, kms.secure_memory.pool_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (kms.secure_memory.memory_pool == MAP_FAILED) {
perror("mmap secure memory");
return -1;
}
// Lock memory to prevent swapping
if (mlock(kms.secure_memory.memory_pool, kms.secure_memory.pool_size) != 0) {
perror("mlock secure memory");
munmap(kms.secure_memory.memory_pool, kms.secure_memory.pool_size);
return -1;
}
// Initialize allocation bitmap
kms.secure_memory.allocation_map = calloc(num_blocks, sizeof(bool));
if (!kms.secure_memory.allocation_map) {
munlock(kms.secure_memory.memory_pool, kms.secure_memory.pool_size);
munmap(kms.secure_memory.memory_pool, kms.secure_memory.pool_size);
return -1;
}
pthread_mutex_init(&kms.secure_memory.pool_lock, NULL);
kms.secure_memory.allocated = 0;
printf("Secure memory pool initialized: %zu bytes\n", kms.secure_memory.pool_size);
return 0;
}
static void cleanup_secure_memory_pool(void)
{
if (kms.secure_memory.memory_pool != MAP_FAILED) {
// Clear memory before releasing
memset(kms.secure_memory.memory_pool, 0, kms.secure_memory.pool_size);
munlock(kms.secure_memory.memory_pool, kms.secure_memory.pool_size);
munmap(kms.secure_memory.memory_pool, kms.secure_memory.pool_size);
}
if (kms.secure_memory.allocation_map) {
free(kms.secure_memory.allocation_map);
}
pthread_mutex_destroy(&kms.secure_memory.pool_lock);
}
static void *secure_malloc(size_t size)
{
pthread_mutex_lock(&kms.secure_memory.pool_lock);
size_t blocks_needed = (size + kms.secure_memory.block_size - 1) / kms.secure_memory.block_size;
size_t total_blocks = kms.secure_memory.pool_size / kms.secure_memory.block_size;
// Find contiguous free blocks
for (size_t i = 0; i <= total_blocks - blocks_needed; i++) {
bool found = true;
for (size_t j = 0; j < blocks_needed; j++) {
if (kms.secure_memory.allocation_map[i + j]) {
found = false;
break;
}
}
if (found) {
// Mark blocks as allocated
for (size_t j = 0; j < blocks_needed; j++) {
kms.secure_memory.allocation_map[i + j] = true;
}
kms.secure_memory.allocated += blocks_needed * kms.secure_memory.block_size;
void *ptr = (uint8_t*)kms.secure_memory.memory_pool + i * kms.secure_memory.block_size;
pthread_mutex_unlock(&kms.secure_memory.pool_lock);
return ptr;
}
}
pthread_mutex_unlock(&kms.secure_memory.pool_lock);
return NULL; // No free blocks
}
static void secure_free(void *ptr, size_t size)
{
if (!ptr) return;
pthread_mutex_lock(&kms.secure_memory.pool_lock);
// Clear memory before freeing
memset(ptr, 0, size);
size_t offset = (uint8_t*)ptr - (uint8_t*)kms.secure_memory.memory_pool;
size_t start_block = offset / kms.secure_memory.block_size;
size_t blocks_to_free = (size + kms.secure_memory.block_size - 1) / kms.secure_memory.block_size;
// Mark blocks as free
for (size_t i = 0; i < blocks_to_free; i++) {
kms.secure_memory.allocation_map[start_block + i] = false;
}
kms.secure_memory.allocated -= blocks_to_free * kms.secure_memory.block_size;
pthread_mutex_unlock(&kms.secure_memory.pool_lock);
}
// Secure random number generation
static int init_hardware_rng(void)
{
// Try to use hardware RNG if available
int rng_fd = open("/dev/hwrng", O_RDONLY);
if (rng_fd >= 0) {
uint8_t test_bytes[16];
if (read(rng_fd, test_bytes, sizeof(test_bytes)) == sizeof(test_bytes)) {
close(rng_fd);
printf("Hardware RNG available\n");
return 0;
}
close(rng_fd);
}
// Fallback to /dev/urandom
printf("Using software RNG\n");
return 0;
}
static int secure_random_bytes(uint8_t *buffer, size_t size)
{
pthread_mutex_lock(&kms.rng.rng_lock);
// Try getrandom() first (Linux 3.17+)
ssize_t result = getrandom(buffer, size, 0);
if (result == (ssize_t)size) {
pthread_mutex_unlock(&kms.rng.rng_lock);
return 0;
}
// Fallback to OpenSSL RAND_bytes
if (RAND_bytes(buffer, size) == 1) {
pthread_mutex_unlock(&kms.rng.rng_lock);
return 0;
}
// Last resort: /dev/urandom
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
pthread_mutex_unlock(&kms.rng.rng_lock);
return -1;
}
size_t total_read = 0;
while (total_read < size) {
ssize_t bytes_read = read(fd, buffer + total_read, size - total_read);
if (bytes_read <= 0) {
close(fd);
pthread_mutex_unlock(&kms.rng.rng_lock);
return -1;
}
total_read += bytes_read;
}
close(fd);
pthread_mutex_unlock(&kms.rng.rng_lock);
return 0;
}
// Key generation functions
static int generate_aes_key(crypto_algorithm_t algorithm, uint8_t **key, size_t *key_size)
{
size_t size;
switch (algorithm) {
case CRYPTO_AES_128_GCM:
case CRYPTO_AES_128_CBC:
size = 16;
break;
case CRYPTO_AES_256_GCM:
case CRYPTO_AES_256_CBC:
size = 32;
break;
default:
return -1;
}
*key = secure_malloc(size);
if (!*key) {
return -1;
}
if (secure_random_bytes(*key, size) != 0) {
secure_free(*key, size);
return -1;
}
*key_size = size;
return 0;
}
static EVP_PKEY *generate_rsa_keypair(int key_size)
{
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!ctx) {
return NULL;
}
if (EVP_PKEY_keygen_init(ctx) <= 0) {
EVP_PKEY_CTX_free(ctx);
return NULL;
}
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, key_size) <= 0) {
EVP_PKEY_CTX_free(ctx);
return NULL;
}
EVP_PKEY *pkey = NULL;
if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
EVP_PKEY_CTX_free(ctx);
return NULL;
}
EVP_PKEY_CTX_free(ctx);
return pkey;
}
static EVP_PKEY *generate_ec_keypair(int curve_nid)
{
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
if (!ctx) {
return NULL;
}
if (EVP_PKEY_keygen_init(ctx) <= 0) {
EVP_PKEY_CTX_free(ctx);
return NULL;
}
if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve_nid) <= 0) {
EVP_PKEY_CTX_free(ctx);
return NULL;
}
EVP_PKEY *pkey = NULL;
if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
EVP_PKEY_CTX_free(ctx);
return NULL;
}
EVP_PKEY_CTX_free(ctx);
return pkey;
}
// Key management functions
static secure_key_t *create_secure_key(key_type_t type, crypto_algorithm_t algorithm)
{
secure_key_t *key = secure_malloc(sizeof(secure_key_t));
if (!key) {
return NULL;
}
key->key_id = ++kms.next_key_id;
key->type = type;
key->algorithm = algorithm;
key->creation_time = time(NULL);
key->expiration_time = key->creation_time + (365 * 24 * 3600); // 1 year
key->usage_count = 0;
key->max_usage = 1000000; // Default max usage
key->revoked = false;
pthread_mutex_init(&key->lock, NULL);
// Generate key material based on algorithm
int result = -1;
switch (algorithm) {
case CRYPTO_AES_128_GCM:
case CRYPTO_AES_128_CBC:
case CRYPTO_AES_256_GCM:
case CRYPTO_AES_256_CBC:
if (kms.hsm.available) {
result = kms.hsm.generate_key(algorithm, &key->key_data, &key->key_size);
} else {
result = generate_aes_key(algorithm, &key->key_data, &key->key_size);
}
break;
case CRYPTO_RSA_2048:
case CRYPTO_RSA_4096: {
int rsa_size = (algorithm == CRYPTO_RSA_2048) ? 2048 : 4096;
EVP_PKEY *pkey = generate_rsa_keypair(rsa_size);
if (pkey) {
// Serialize private key
BIO *bio = BIO_new(BIO_s_mem());
if (PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
BUF_MEM *bio_mem;
BIO_get_mem_ptr(bio, &bio_mem);
key->key_size = bio_mem->length;
key->key_data = secure_malloc(key->key_size);
if (key->key_data) {
memcpy(key->key_data, bio_mem->data, key->key_size);
result = 0;
}
}
BIO_free(bio);
EVP_PKEY_free(pkey);
}
break;
}
case CRYPTO_ECDSA_P256:
case CRYPTO_ECDSA_P384:
case CRYPTO_ECDSA_P521:
case CRYPTO_ECDH_P256:
case CRYPTO_ECDH_P384: {
int curve_nid;
switch (algorithm) {
case CRYPTO_ECDSA_P256:
case CRYPTO_ECDH_P256:
curve_nid = NID_X9_62_prime256v1;
break;
case CRYPTO_ECDSA_P384:
case CRYPTO_ECDH_P384:
curve_nid = NID_secp384r1;
break;
case CRYPTO_ECDSA_P521:
curve_nid = NID_secp521r1;
break;
default:
curve_nid = NID_X9_62_prime256v1;
break;
}
EVP_PKEY *pkey = generate_ec_keypair(curve_nid);
if (pkey) {
// Serialize private key
BIO *bio = BIO_new(BIO_s_mem());
if (PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
BUF_MEM *bio_mem;
BIO_get_mem_ptr(bio, &bio_mem);
key->key_size = bio_mem->length;
key->key_data = secure_malloc(key->key_size);
if (key->key_data) {
memcpy(key->key_data, bio_mem->data, key->key_size);
result = 0;
}
}
BIO_free(bio);
EVP_PKEY_free(pkey);
}
break;
}
default:
break;
}
if (result != 0) {
pthread_mutex_destroy(&key->lock);
secure_free(key, sizeof(secure_key_t));
return NULL;
}
return key;
}
static void destroy_secure_key(secure_key_t *key)
{
if (!key) return;
pthread_mutex_lock(&key->lock);
if (key->key_data) {
secure_free(key->key_data, key->key_size);
}
pthread_mutex_unlock(&key->lock);
pthread_mutex_destroy(&key->lock);
secure_free(key, sizeof(secure_key_t));
}
static int store_key(secure_key_t *key)
{
pthread_rwlock_wrlock(&kms.keys_lock);
for (int i = 0; i < MAX_KEYS; i++) {
if (!kms.keys[i]) {
kms.keys[i] = key;
pthread_rwlock_unlock(&kms.keys_lock);
return 0;
}
}
pthread_rwlock_unlock(&kms.keys_lock);
return -1; // No space
}
static secure_key_t *find_key(uint32_t key_id)
{
pthread_rwlock_rdlock(&kms.keys_lock);
secure_key_t *key = NULL;
for (int i = 0; i < MAX_KEYS; i++) {
if (kms.keys[i] && kms.keys[i]->key_id == key_id && !kms.keys[i]->revoked) {
key = kms.keys[i];
break;
}
}
pthread_rwlock_unlock(&kms.keys_lock);
return key;
}
// Encryption/Decryption functions
static int aes_gcm_encrypt(const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size,
const uint8_t *plaintext, size_t plaintext_size,
const uint8_t *aad, size_t aad_size,
uint8_t **ciphertext, size_t *ciphertext_size,
uint8_t *tag, size_t *tag_size)
{
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) return -1;
const EVP_CIPHER *cipher;
switch (key_size) {
case 16:
cipher = EVP_aes_128_gcm();
break;
case 32:
cipher = EVP_aes_256_gcm();
break;
default:
EVP_CIPHER_CTX_free(ctx);
return -1;
}
// Initialize encryption
if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1) {
EVP_CIPHER_CTX_free(ctx);
return -1;
}
// Set IV length
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_size, NULL) != 1) {
EVP_CIPHER_CTX_free(ctx);
return -1;
}
// Set key and IV
if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv) != 1) {
EVP_CIPHER_CTX_free(ctx);
return -1;
}
*ciphertext = secure_malloc(plaintext_size);
if (!*ciphertext) {
EVP_CIPHER_CTX_free(ctx);
return -1;
}
int len;
int ciphertext_len = 0;
// Add AAD if present
if (aad && aad_size > 0) {
if (EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_size) != 1) {
secure_free(*ciphertext, plaintext_size);
EVP_CIPHER_CTX_free(ctx);
return -1;
}
}
// Encrypt plaintext
if (EVP_EncryptUpdate(ctx, *ciphertext, &len, plaintext, plaintext_size) != 1) {
secure_free(*ciphertext, plaintext_size);
EVP_CIPHER_CTX_free(ctx);
return -1;
}
ciphertext_len = len;
// Finalize encryption
if (EVP_EncryptFinal_ex(ctx, *ciphertext + len, &len) != 1) {
secure_free(*ciphertext, plaintext_size);
EVP_CIPHER_CTX_free(ctx);
return -1;
}
ciphertext_len += len;
// Get authentication tag
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag) != 1) {
secure_free(*ciphertext, plaintext_size);
EVP_CIPHER_CTX_free(ctx);
return -1;
}
*ciphertext_size = ciphertext_len;
*tag_size = 16;
EVP_CIPHER_CTX_free(ctx);
return 0;
}
static int aes_gcm_decrypt(const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size,
const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *aad, size_t aad_size,
const uint8_t *tag, size_t tag_size,
uint8_t **plaintext, size_t *plaintext_size)
{
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) return -1;
const EVP_CIPHER *cipher;
switch (key_size) {
case 16:
cipher = EVP_aes_128_gcm();
break;
case 32:
cipher = EVP_aes_256_gcm();
break;
default:
EVP_CIPHER_CTX_free(ctx);
return -1;
}
// Initialize decryption
if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1) {
EVP_CIPHER_CTX_free(ctx);
return -1;
}
// Set IV length
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_size, NULL) != 1) {
EVP_CIPHER_CTX_free(ctx);
return -1;
}
// Set key and IV
if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv) != 1) {
EVP_CIPHER_CTX_free(ctx);
return -1;
}
*plaintext = secure_malloc(ciphertext_size);
if (!*plaintext) {
EVP_CIPHER_CTX_free(ctx);
return -1;
}
int len;
int plaintext_len = 0;
// Add AAD if present
if (aad && aad_size > 0) {
if (EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_size) != 1) {
secure_free(*plaintext, ciphertext_size);
EVP_CIPHER_CTX_free(ctx);
return -1;
}
}
// Decrypt ciphertext
if (EVP_DecryptUpdate(ctx, *plaintext, &len, ciphertext, ciphertext_size) != 1) {
secure_free(*plaintext, ciphertext_size);
EVP_CIPHER_CTX_free(ctx);
return -1;
}
plaintext_len = len;
// Set expected authentication tag
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_size, (void*)tag) != 1) {
secure_free(*plaintext, ciphertext_size);
EVP_CIPHER_CTX_free(ctx);
return -1;
}
// Finalize decryption and verify authentication
int ret = EVP_DecryptFinal_ex(ctx, *plaintext + len, &len);
if (ret <= 0) {
// Authentication failed
secure_free(*plaintext, ciphertext_size);
EVP_CIPHER_CTX_free(ctx);
return -1;
}
plaintext_len += len;
*plaintext_size = plaintext_len;
EVP_CIPHER_CTX_free(ctx);
return 0;
}
// Digital signature functions
static int rsa_sign(EVP_PKEY *private_key, const uint8_t *data, size_t data_size,
uint8_t **signature, size_t *signature_size)
{
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) return -1;
if (EVP_DigestSignInit(ctx, NULL, EVP_sha256(), NULL, private_key) != 1) {
EVP_MD_CTX_free(ctx);
return -1;
}
if (EVP_DigestSignUpdate(ctx, data, data_size) != 1) {
EVP_MD_CTX_free(ctx);
return -1;
}
// Get signature length
size_t sig_len;
if (EVP_DigestSignFinal(ctx, NULL, &sig_len) != 1) {
EVP_MD_CTX_free(ctx);
return -1;
}
*signature = secure_malloc(sig_len);
if (!*signature) {
EVP_MD_CTX_free(ctx);
return -1;
}
if (EVP_DigestSignFinal(ctx, *signature, &sig_len) != 1) {
secure_free(*signature, sig_len);
EVP_MD_CTX_free(ctx);
return -1;
}
*signature_size = sig_len;
EVP_MD_CTX_free(ctx);
return 0;
}
static int rsa_verify(EVP_PKEY *public_key, const uint8_t *data, size_t data_size,
const uint8_t *signature, size_t signature_size)
{
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) return -1;
if (EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, public_key) != 1) {
EVP_MD_CTX_free(ctx);
return -1;
}
if (EVP_DigestVerifyUpdate(ctx, data, data_size) != 1) {
EVP_MD_CTX_free(ctx);
return -1;
}
int ret = EVP_DigestVerifyFinal(ctx, signature, signature_size);
EVP_MD_CTX_free(ctx);
return (ret == 1) ? 0 : -1;
}
// Key derivation functions
static int pbkdf2_derive_key(const char *password, size_t password_len,
const uint8_t *salt, size_t salt_len,
int iterations, size_t key_len,
uint8_t **derived_key)
{
*derived_key = secure_malloc(key_len);
if (!*derived_key) {
return -1;
}
if (PKCS5_PBKDF2_HMAC(password, password_len, salt, salt_len,
iterations, EVP_sha256(), key_len, *derived_key) != 1) {
secure_free(*derived_key, key_len);
return -1;
}
return 0;
}
static int hkdf_derive_key(const uint8_t *ikm, size_t ikm_len,
const uint8_t *salt, size_t salt_len,
const uint8_t *info, size_t info_len,
size_t key_len, uint8_t **derived_key)
{
*derived_key = secure_malloc(key_len);
if (!*derived_key) {
return -1;
}
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
if (!ctx) {
secure_free(*derived_key, key_len);
return -1;
}
if (EVP_PKEY_derive_init(ctx) != 1) {
EVP_PKEY_CTX_free(ctx);
secure_free(*derived_key, key_len);
return -1;
}
if (EVP_PKEY_CTX_set_hkdf_md(ctx, EVP_sha256()) != 1) {
EVP_PKEY_CTX_free(ctx);
secure_free(*derived_key, key_len);
return -1;
}
if (EVP_PKEY_CTX_set1_hkdf_key(ctx, ikm, ikm_len) != 1) {
EVP_PKEY_CTX_free(ctx);
secure_free(*derived_key, key_len);
return -1;
}
if (salt && salt_len > 0) {
if (EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, salt_len) != 1) {
EVP_PKEY_CTX_free(ctx);
secure_free(*derived_key, key_len);
return -1;
}
}
if (info && info_len > 0) {
if (EVP_PKEY_CTX_add1_hkdf_info(ctx, info, info_len) != 1) {
EVP_PKEY_CTX_free(ctx);
secure_free(*derived_key, key_len);
return -1;
}
}
size_t out_len = key_len;
if (EVP_PKEY_derive(ctx, *derived_key, &out_len) != 1) {
EVP_PKEY_CTX_free(ctx);
secure_free(*derived_key, key_len);
return -1;
}
EVP_PKEY_CTX_free(ctx);
return 0;
}
// High-level API functions
uint32_t crypto_generate_key(crypto_algorithm_t algorithm)
{
key_type_t key_type;
switch (algorithm) {
case CRYPTO_AES_128_GCM:
case CRYPTO_AES_256_GCM:
case CRYPTO_AES_128_CBC:
case CRYPTO_AES_256_CBC:
case CRYPTO_CHACHA20_POLY1305:
key_type = KEY_TYPE_SYMMETRIC;
break;
case CRYPTO_RSA_2048:
case CRYPTO_RSA_4096:
key_type = KEY_TYPE_RSA_PRIVATE;
break;
case CRYPTO_ECDSA_P256:
case CRYPTO_ECDSA_P384:
case CRYPTO_ECDSA_P521:
case CRYPTO_ECDH_P256:
case CRYPTO_ECDH_P384:
key_type = KEY_TYPE_EC_PRIVATE;
break;
default:
return 0;
}
secure_key_t *key = create_secure_key(key_type, algorithm);
if (!key) {
return 0;
}
if (store_key(key) != 0) {
destroy_secure_key(key);
return 0;
}
return key->key_id;
}
int crypto_encrypt(uint32_t key_id, const uint8_t *plaintext, size_t plaintext_size,
const uint8_t *aad, size_t aad_size,
uint8_t **ciphertext, size_t *ciphertext_size,
uint8_t *iv, size_t *iv_size,
uint8_t *tag, size_t *tag_size)
{
secure_key_t *key = find_key(key_id);
if (!key) {
return -1;
}
pthread_mutex_lock(&key->lock);
// Check key validity
time_t now = time(NULL);
if (key->revoked || now > key->expiration_time ||
key->usage_count >= key->max_usage) {
pthread_mutex_unlock(&key->lock);
return -1;
}
int result = -1;
switch (key->algorithm) {
case CRYPTO_AES_128_GCM:
case CRYPTO_AES_256_GCM:
// Generate random IV
*iv_size = 12; // 96-bit IV for GCM
if (secure_random_bytes(iv, *iv_size) != 0) {
break;
}
if (kms.hsm.available) {
result = kms.hsm.encrypt(key->key_data, key->key_size,
plaintext, plaintext_size,
ciphertext, ciphertext_size);
} else {
result = aes_gcm_encrypt(key->key_data, key->key_size,
iv, *iv_size,
plaintext, plaintext_size,
aad, aad_size,
ciphertext, ciphertext_size,
tag, tag_size);
}
break;
case CRYPTO_AES_128_CBC:
case CRYPTO_AES_256_CBC:
// Generate random IV
*iv_size = 16; // 128-bit IV for CBC
if (secure_random_bytes(iv, *iv_size) != 0) {
break;
}
// Implement CBC mode encryption
// ... (implementation details)
break;
default:
break;
}
if (result == 0) {
key->usage_count++;
}
pthread_mutex_unlock(&key->lock);
return result;
}
int crypto_decrypt(uint32_t key_id, const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *aad, size_t aad_size,
const uint8_t *iv, size_t iv_size,
const uint8_t *tag, size_t tag_size,
uint8_t **plaintext, size_t *plaintext_size)
{
secure_key_t *key = find_key(key_id);
if (!key) {
return -1;
}
pthread_mutex_lock(&key->lock);
// Check key validity
time_t now = time(NULL);
if (key->revoked || now > key->expiration_time ||
key->usage_count >= key->max_usage) {
pthread_mutex_unlock(&key->lock);
return -1;
}
int result = -1;
switch (key->algorithm) {
case CRYPTO_AES_128_GCM:
case CRYPTO_AES_256_GCM:
if (kms.hsm.available) {
result = kms.hsm.decrypt(key->key_data, key->key_size,
ciphertext, ciphertext_size,
plaintext, plaintext_size);
} else {
result = aes_gcm_decrypt(key->key_data, key->key_size,
iv, iv_size,
ciphertext, ciphertext_size,
aad, aad_size,
tag, tag_size,
plaintext, plaintext_size);
}
break;
case CRYPTO_AES_128_CBC:
case CRYPTO_AES_256_CBC:
// Implement CBC mode decryption
// ... (implementation details)
break;
default:
break;
}
if (result == 0) {
key->usage_count++;
}
pthread_mutex_unlock(&key->lock);
return result;
}
int crypto_sign(uint32_t key_id, const uint8_t *data, size_t data_size,
uint8_t **signature, size_t *signature_size)
{
secure_key_t *key = find_key(key_id);
if (!key || key->type != KEY_TYPE_RSA_PRIVATE) {
return -1;
}
pthread_mutex_lock(&key->lock);
// Check key validity
time_t now = time(NULL);
if (key->revoked || now > key->expiration_time ||
key->usage_count >= key->max_usage) {
pthread_mutex_unlock(&key->lock);
return -1;
}
// Load private key from stored data
BIO *bio = BIO_new_mem_buf(key->key_data, key->key_size);
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!pkey) {
pthread_mutex_unlock(&key->lock);
return -1;
}
int result = rsa_sign(pkey, data, data_size, signature, signature_size);
if (result == 0) {
key->usage_count++;
}
EVP_PKEY_free(pkey);
pthread_mutex_unlock(&key->lock);
return result;
}
int crypto_verify(uint32_t key_id, const uint8_t *data, size_t data_size,
const uint8_t *signature, size_t signature_size)
{
secure_key_t *key = find_key(key_id);
if (!key) {
return -1;
}
pthread_mutex_lock(&key->lock);
// Check key validity
time_t now = time(NULL);
if (key->revoked || now > key->expiration_time) {
pthread_mutex_unlock(&key->lock);
return -1;
}
// Load key from stored data
BIO *bio = BIO_new_mem_buf(key->key_data, key->key_size);
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
if (!pkey) {
BIO_free(bio);
bio = BIO_new_mem_buf(key->key_data, key->key_size);
pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
}
BIO_free(bio);
if (!pkey) {
pthread_mutex_unlock(&key->lock);
return -1;
}
int result = rsa_verify(pkey, data, data_size, signature, signature_size);
if (result == 0) {
key->usage_count++;
}
EVP_PKEY_free(pkey);
pthread_mutex_unlock(&key->lock);
return result;
}
void crypto_revoke_key(uint32_t key_id)
{
secure_key_t *key = find_key(key_id);
if (!key) {
return;
}
pthread_mutex_lock(&key->lock);
key->revoked = true;
pthread_mutex_unlock(&key->lock);
}
// Secure hash functions
int crypto_hash_sha256(const uint8_t *data, size_t data_size, uint8_t hash[32])
{
SHA256_CTX ctx;
if (SHA256_Init(&ctx) != 1) {
return -1;
}
if (SHA256_Update(&ctx, data, data_size) != 1) {
return -1;
}
if (SHA256_Final(hash, &ctx) != 1) {
return -1;
}
return 0;
}
int crypto_hmac_sha256(const uint8_t *key, size_t key_size,
const uint8_t *data, size_t data_size,
uint8_t hmac[32])
{
unsigned int hmac_len;
if (!HMAC(EVP_sha256(), key, key_size, data, data_size, hmac, &hmac_len)) {
return -1;
}
return (hmac_len == 32) ? 0 : -1;
}
// Initialization and cleanup
static int init_crypto_framework(void)
{
// Initialize OpenSSL
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
// Initialize secure memory pool
if (init_secure_memory_pool() != 0) {
return -1;
}
// Initialize random number generator
pthread_mutex_init(&kms.rng.rng_lock, NULL);
if (init_hardware_rng() != 0) {
cleanup_secure_memory_pool();
return -1;
}
// Initialize key management
pthread_rwlock_init(&kms.keys_lock, NULL);
kms.next_key_id = 1;
// Try to initialize HSM (optional)
kms.hsm.available = false;
// ... HSM initialization code would go here
printf("Cryptographic framework initialized\n");
return 0;
}
static void cleanup_crypto_framework(void)
{
// Clean up keys
pthread_rwlock_wrlock(&kms.keys_lock);
for (int i = 0; i < MAX_KEYS; i++) {
if (kms.keys[i]) {
destroy_secure_key(kms.keys[i]);
kms.keys[i] = NULL;
}
}
pthread_rwlock_unlock(&kms.keys_lock);
pthread_rwlock_destroy(&kms.keys_lock);
// Clean up HSM
if (kms.hsm.available && kms.hsm.cleanup) {
kms.hsm.cleanup();
}
// Clean up RNG
pthread_mutex_destroy(&kms.rng.rng_lock);
// Clean up secure memory
cleanup_secure_memory_pool();
// Clean up OpenSSL
EVP_cleanup();
ERR_free_strings();
printf("Cryptographic framework cleanup completed\n");
}
// Example usage and testing
static void test_crypto_framework(void)
{
printf("Testing cryptographic framework...\n");
// Test AES-256-GCM encryption
uint32_t key_id = crypto_generate_key(CRYPTO_AES_256_GCM);
if (key_id == 0) {
printf("Failed to generate AES key\n");
return;
}
const char *plaintext = "Hello, secure world!";
size_t plaintext_size = strlen(plaintext);
uint8_t *ciphertext;
size_t ciphertext_size;
uint8_t iv[16];
size_t iv_size;
uint8_t tag[16];
size_t tag_size;
int result = crypto_encrypt(key_id, (const uint8_t*)plaintext, plaintext_size,
NULL, 0, &ciphertext, &ciphertext_size,
iv, &iv_size, tag, &tag_size);
if (result == 0) {
printf("Encryption successful: %zu bytes\n", ciphertext_size);
uint8_t *decrypted;
size_t decrypted_size;
result = crypto_decrypt(key_id, ciphertext, ciphertext_size,
NULL, 0, iv, iv_size, tag, tag_size,
&decrypted, &decrypted_size);
if (result == 0 && decrypted_size == plaintext_size &&
memcmp(decrypted, plaintext, plaintext_size) == 0) {
printf("Decryption successful: '%.*s'\n", (int)decrypted_size, decrypted);
} else {
printf("Decryption failed\n");
}
secure_free(decrypted, decrypted_size);
secure_free(ciphertext, ciphertext_size);
} else {
printf("Encryption failed\n");
}
// Test RSA signing
uint32_t rsa_key_id = crypto_generate_key(CRYPTO_RSA_2048);
if (rsa_key_id != 0) {
uint8_t *signature;
size_t signature_size;
result = crypto_sign(rsa_key_id, (const uint8_t*)plaintext, plaintext_size,
&signature, &signature_size);
if (result == 0) {
printf("Signing successful: %zu bytes\n", signature_size);
result = crypto_verify(rsa_key_id, (const uint8_t*)plaintext, plaintext_size,
signature, signature_size);
if (result == 0) {
printf("Signature verification successful\n");
} else {
printf("Signature verification failed\n");
}
secure_free(signature, signature_size);
} else {
printf("Signing failed\n");
}
}
// Test key derivation
const char *password = "secure_password";
uint8_t salt[16];
secure_random_bytes(salt, sizeof(salt));
uint8_t *derived_key;
result = pbkdf2_derive_key(password, strlen(password), salt, sizeof(salt),
100000, 32, &derived_key);
if (result == 0) {
printf("Key derivation successful\n");
secure_free(derived_key, 32);
} else {
printf("Key derivation failed\n");
}
crypto_revoke_key(key_id);
crypto_revoke_key(rsa_key_id);
printf("Cryptographic framework test completed\n");
}
// Main function
int main(void)
{
if (init_crypto_framework() != 0) {
fprintf(stderr, "Failed to initialize cryptographic framework\n");
return 1;
}
test_crypto_framework();
cleanup_crypto_framework();
return 0;
}
SELinux Security Module Development
Advanced SELinux Policy and Module Framework
// selinux_framework.c - Advanced SELinux development framework
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/xattr.h>
#include <linux/capability.h>
#include <sys/capability.h>
#include <selinux/selinux.h>
#include <selinux/label.h>
#include <selinux/restorecon.h>
#include <selinux/context.h>
#include <selinux/avc.h>
#include <selinux/get_context_list.h>
#include <selinux/get_default_type.h>
#include <selinux/flask.h>
#define MAX_CONTEXT_SIZE 256
#define MAX_PATH_SIZE 4096
#define MAX_RULES 10000
// SELinux security class and permission mappings
typedef struct {
const char *class_name;
security_class_t class_id;
const char **perms;
int num_perms;
} security_class_info_t;
// Custom security policy rule
typedef struct {
char source_type[64];
char target_type[64];
char object_class[32];
char permission[32];
int allow; // 1 for allow, 0 for deny
} policy_rule_t;
// SELinux context management
typedef struct {
char user[64];
char role[64];
char type[64];
char level[64];
char full_context[MAX_CONTEXT_SIZE];
} selinux_context_t;
// Application security profile
typedef struct {
char app_name[64];
char domain_type[64];
char exec_type[64];
char data_type[64];
char config_type[64];
char log_type[64];
// Permissions needed
char **required_permissions;
int num_permissions;
// Network access
bool network_client;
bool network_server;
int *allowed_ports;
int num_ports;
// File access patterns
char **read_paths;
char **write_paths;
char **execute_paths;
int num_read_paths;
int num_write_paths;
int num_execute_paths;
} app_security_profile_t;
// Global SELinux framework context
static struct {
bool enforcing;
bool enabled;
struct selabel_handle *file_contexts;
struct avc_entry_ref avc_cache;
policy_rule_t rules[MAX_RULES];
int num_rules;
app_security_profile_t *profiles;
int num_profiles;
} selinux_ctx = {0};
// Permission mappings for common security classes
static const char *file_perms[] = {
"read", "write", "execute", "getattr", "setattr", "lock",
"relabelfrom", "relabelto", "append", "unlink", "link",
"rename", "create", "mounton", "quotaon", "audit_access"
};
static const char *process_perms[] = {
"fork", "transition", "sigchld", "sigkill", "sigstop",
"signull", "signal", "ptrace", "getsched", "setsched",
"getsession", "getpgid", "setpgid", "getcap", "setcap"
};
static const char *socket_perms[] = {
"create", "bind", "connect", "listen", "accept", "getopt",
"setopt", "shutdown", "recvfrom", "sendto", "recv_msg",
"send_msg", "name_bind", "name_connect"
};
static security_class_info_t security_classes[] = {
{"file", SECCLASS_FILE, file_perms, sizeof(file_perms)/sizeof(file_perms[0])},
{"process", SECCLASS_PROCESS, process_perms, sizeof(process_perms)/sizeof(process_perms[0])},
{"socket", SECCLASS_SOCKET, socket_perms, sizeof(socket_perms)/sizeof(socket_perms[0])},
};
// Utility functions
static int parse_selinux_context(const char *context_str, selinux_context_t *ctx)
{
context_t context = context_new(context_str);
if (!context) {
return -1;
}
const char *user = context_user_get(context);
const char *role = context_role_get(context);
const char *type = context_type_get(context);
const char *level = context_range_get(context);
if (user) strncpy(ctx->user, user, sizeof(ctx->user) - 1);
if (role) strncpy(ctx->role, role, sizeof(ctx->role) - 1);
if (type) strncpy(ctx->type, type, sizeof(ctx->type) - 1);
if (level) strncpy(ctx->level, level, sizeof(ctx->level) - 1);
strncpy(ctx->full_context, context_str, sizeof(ctx->full_context) - 1);
context_free(context);
return 0;
}
static int build_selinux_context(const selinux_context_t *ctx, char *context_str, size_t size)
{
snprintf(context_str, size, "%s:%s:%s:%s",
ctx->user, ctx->role, ctx->type, ctx->level);
return 0;
}
static security_class_t get_security_class_id(const char *class_name)
{
for (size_t i = 0; i < sizeof(security_classes)/sizeof(security_classes[0]); i++) {
if (strcmp(security_classes[i].class_name, class_name) == 0) {
return security_classes[i].class_id;
}
}
return 0;
}
static access_vector_t get_permission_bit(security_class_t class_id, const char *perm_name)
{
for (size_t i = 0; i < sizeof(security_classes)/sizeof(security_classes[0]); i++) {
if (security_classes[i].class_id == class_id) {
for (int j = 0; j < security_classes[i].num_perms; j++) {
if (strcmp(security_classes[i].perms[j], perm_name) == 0) {
return 1 << j;
}
}
break;
}
}
return 0;
}
// SELinux policy management
static int load_policy_rule(const char *source, const char *target,
const char *class, const char *perm, int allow)
{
if (selinux_ctx.num_rules >= MAX_RULES) {
return -1;
}
policy_rule_t *rule = &selinux_ctx.rules[selinux_ctx.num_rules];
strncpy(rule->source_type, source, sizeof(rule->source_type) - 1);
strncpy(rule->target_type, target, sizeof(rule->target_type) - 1);
strncpy(rule->object_class, class, sizeof(rule->object_class) - 1);
strncpy(rule->permission, perm, sizeof(rule->permission) - 1);
rule->allow = allow;
selinux_ctx.num_rules++;
return 0;
}
static int check_policy_rule(const char *source, const char *target,
const char *class, const char *perm)
{
for (int i = 0; i < selinux_ctx.num_rules; i++) {
policy_rule_t *rule = &selinux_ctx.rules[i];
if (strcmp(rule->source_type, source) == 0 &&
strcmp(rule->target_type, target) == 0 &&
strcmp(rule->object_class, class) == 0 &&
strcmp(rule->permission, perm) == 0) {
return rule->allow;
}
}
return -1; // Rule not found
}
// File context management
static int set_file_context(const char *path, const char *context)
{
if (setfilecon(path, context) < 0) {
perror("setfilecon");
return -1;
}
printf("Set context '%s' on file '%s'\n", context, path);
return 0;
}
static int get_file_context(const char *path, char *context, size_t context_size)
{
char *file_context = NULL;
if (getfilecon(path, &file_context) < 0) {
perror("getfilecon");
return -1;
}
strncpy(context, file_context, context_size - 1);
context[context_size - 1] = '\0';
freecon(file_context);
return 0;
}
static int restore_file_contexts(const char *path)
{
if (selinux_restorecon(path, SELINUX_RESTORECON_RECURSE) < 0) {
perror("selinux_restorecon");
return -1;
}
printf("Restored contexts for '%s'\n", path);
return 0;
}
// Process context management
static int get_process_context(pid_t pid, char *context, size_t context_size)
{
char *proc_context = NULL;
if (getpidcon(pid, &proc_context) < 0) {
perror("getpidcon");
return -1;
}
strncpy(context, proc_context, context_size - 1);
context[context_size - 1] = '\0';
freecon(proc_context);
return 0;
}
static int set_process_context(const char *context)
{
if (setcon(context) < 0) {
perror("setcon");
return -1;
}
printf("Set process context to '%s'\n", context);
return 0;
}
static int transition_to_context(const char *new_context)
{
char current_context[MAX_CONTEXT_SIZE];
if (getcon(current_context) < 0) {
perror("getcon");
return -1;
}
printf("Transitioning from '%s' to '%s'\n", current_context, new_context);
if (setcon(new_context) < 0) {
perror("setcon");
return -1;
}
return 0;
}
// Access control checking
static int check_access(const char *source_context, const char *target_context,
const char *class_name, const char *permission)
{
security_class_t class_id = get_security_class_id(class_name);
if (class_id == 0) {
fprintf(stderr, "Unknown security class: %s\n", class_name);
return -1;
}
access_vector_t perm_bit = get_permission_bit(class_id, permission);
if (perm_bit == 0) {
fprintf(stderr, "Unknown permission: %s for class %s\n", permission, class_name);
return -1;
}
int result = avc_has_perm_noaudit(source_context, target_context,
class_id, perm_bit, &selinux_ctx.avc_cache, NULL);
if (result == 0) {
printf("Access GRANTED: %s -> %s (%s:%s)\n",
source_context, target_context, class_name, permission);
} else {
printf("Access DENIED: %s -> %s (%s:%s)\n",
source_context, target_context, class_name, permission);
}
return result;
}
static int check_file_access(const char *path, const char *permission)
{
char current_context[MAX_CONTEXT_SIZE];
char file_context[MAX_CONTEXT_SIZE];
if (getcon(current_context) < 0) {
perror("getcon");
return -1;
}
if (get_file_context(path, file_context, sizeof(file_context)) < 0) {
return -1;
}
return check_access(current_context, file_context, "file", permission);
}
// Application security profile management
static app_security_profile_t *create_app_profile(const char *app_name)
{
app_security_profile_t *profile = malloc(sizeof(app_security_profile_t));
if (!profile) {
return NULL;
}
memset(profile, 0, sizeof(app_security_profile_t));
strncpy(profile->app_name, app_name, sizeof(profile->app_name) - 1);
// Generate default type names
snprintf(profile->domain_type, sizeof(profile->domain_type), "%s_t", app_name);
snprintf(profile->exec_type, sizeof(profile->exec_type), "%s_exec_t", app_name);
snprintf(profile->data_type, sizeof(profile->data_type), "%s_data_t", app_name);
snprintf(profile->config_type, sizeof(profile->config_type), "%s_config_t", app_name);
snprintf(profile->log_type, sizeof(profile->log_type), "%s_log_t", app_name);
return profile;
}
static void destroy_app_profile(app_security_profile_t *profile)
{
if (!profile) return;
if (profile->required_permissions) {
for (int i = 0; i < profile->num_permissions; i++) {
free(profile->required_permissions[i]);
}
free(profile->required_permissions);
}
if (profile->allowed_ports) {
free(profile->allowed_ports);
}
if (profile->read_paths) {
for (int i = 0; i < profile->num_read_paths; i++) {
free(profile->read_paths[i]);
}
free(profile->read_paths);
}
if (profile->write_paths) {
for (int i = 0; i < profile->num_write_paths; i++) {
free(profile->write_paths[i]);
}
free(profile->write_paths);
}
if (profile->execute_paths) {
for (int i = 0; i < profile->num_execute_paths; i++) {
free(profile->execute_paths[i]);
}
free(profile->execute_paths);
}
free(profile);
}
static int add_permission_to_profile(app_security_profile_t *profile, const char *permission)
{
char **new_perms = realloc(profile->required_permissions,
(profile->num_permissions + 1) * sizeof(char*));
if (!new_perms) {
return -1;
}
new_perms[profile->num_permissions] = strdup(permission);
if (!new_perms[profile->num_permissions]) {
return -1;
}
profile->required_permissions = new_perms;
profile->num_permissions++;
return 0;
}
static int add_file_access_to_profile(app_security_profile_t *profile,
const char *path, const char *access_type)
{
char ***path_array;
int *count;
if (strcmp(access_type, "read") == 0) {
path_array = &profile->read_paths;
count = &profile->num_read_paths;
} else if (strcmp(access_type, "write") == 0) {
path_array = &profile->write_paths;
count = &profile->num_write_paths;
} else if (strcmp(access_type, "execute") == 0) {
path_array = &profile->execute_paths;
count = &profile->num_execute_paths;
} else {
return -1;
}
char **new_paths = realloc(*path_array, (*count + 1) * sizeof(char*));
if (!new_paths) {
return -1;
}
new_paths[*count] = strdup(path);
if (!new_paths[*count]) {
return -1;
}
*path_array = new_paths;
(*count)++;
return 0;
}
// SELinux policy generation
static int generate_type_enforcement_rules(app_security_profile_t *profile, FILE *output)
{
fprintf(output, "# Type enforcement rules for %s\n", profile->app_name);
// Domain type declaration
fprintf(output, "type %s;\n", profile->domain_type);
fprintf(output, "domain_type(%s)\n", profile->domain_type);
// File type declarations
fprintf(output, "type %s;\n", profile->exec_type);
fprintf(output, "application_executable_file(%s)\n", profile->exec_type);
fprintf(output, "type %s;\n", profile->data_type);
fprintf(output, "application_data_file(%s)\n", profile->data_type);
fprintf(output, "type %s;\n", profile->config_type);
fprintf(output, "application_configuration_file(%s)\n", profile->config_type);
fprintf(output, "type %s;\n", profile->log_type);
fprintf(output, "logging_type(%s)\n", profile->log_type);
// Domain transition rule
fprintf(output, "application_domain(%s, %s)\n", profile->domain_type, profile->exec_type);
// File access rules
for (int i = 0; i < profile->num_read_paths; i++) {
fprintf(output, "allow %s %s:file { read getattr };\n",
profile->domain_type, profile->data_type);
}
for (int i = 0; i < profile->num_write_paths; i++) {
fprintf(output, "allow %s %s:file { write create unlink };\n",
profile->domain_type, profile->data_type);
}
// Network access rules
if (profile->network_client) {
fprintf(output, "allow %s self:tcp_socket { create connect };\n", profile->domain_type);
fprintf(output, "allow %s self:udp_socket { create connect };\n", profile->domain_type);
}
if (profile->network_server) {
fprintf(output, "allow %s self:tcp_socket { create bind listen accept };\n", profile->domain_type);
fprintf(output, "allow %s self:udp_socket { create bind };\n", profile->domain_type);
for (int i = 0; i < profile->num_ports; i++) {
fprintf(output, "allow %s port_t:tcp_socket name_bind; # port %d\n",
profile->domain_type, profile->allowed_ports[i]);
}
}
fprintf(output, "\n");
return 0;
}
static int generate_file_contexts(app_security_profile_t *profile, FILE *output)
{
fprintf(output, "# File contexts for %s\n", profile->app_name);
// Executable context
fprintf(output, "/usr/bin/%s\\.*\t\tsystem_u:object_r:%s:s0\n",
profile->app_name, profile->exec_type);
// Data directory contexts
fprintf(output, "/var/lib/%s(/.*)?\\.*\t\tsystem_u:object_r:%s:s0\n",
profile->app_name, profile->data_type);
// Configuration contexts
fprintf(output, "/etc/%s(/.*)?\\.*\t\tsystem_u:object_r:%s:s0\n",
profile->app_name, profile->config_type);
// Log contexts
fprintf(output, "/var/log/%s(/.*)?\\.*\t\tsystem_u:object_r:%s:s0\n",
profile->app_name, profile->log_type);
fprintf(output, "\n");
return 0;
}
// Security audit and compliance
static int audit_file_contexts(const char *directory)
{
printf("Auditing file contexts in %s\n", directory);
char command[1024];
snprintf(command, sizeof(command), "find %s -exec ls -Z {} \\;", directory);
FILE *fp = popen(command, "r");
if (!fp) {
perror("popen");
return -1;
}
char line[1024];
int violations = 0;
while (fgets(line, sizeof(line), fp)) {
// Parse and check contexts
// This is a simplified check - real implementation would be more comprehensive
if (strstr(line, "unlabeled_t") || strstr(line, "default_t")) {
printf("VIOLATION: %s", line);
violations++;
}
}
pclose(fp);
printf("Audit completed: %d violations found\n", violations);
return violations;
}
static int check_process_compliance(void)
{
printf("Checking process compliance\n");
FILE *fp = popen("ps -eZ", "r");
if (!fp) {
perror("popen");
return -1;
}
char line[1024];
int violations = 0;
while (fgets(line, sizeof(line), fp)) {
// Check for processes running in unconfined domains
if (strstr(line, "unconfined_t") && !strstr(line, "kernel")) {
printf("UNCONFINED PROCESS: %s", line);
violations++;
}
}
pclose(fp);
printf("Process compliance check completed: %d violations found\n", violations);
return violations;
}
// Main framework initialization
static int init_selinux_framework(void)
{
// Check if SELinux is enabled
if (!is_selinux_enabled()) {
fprintf(stderr, "SELinux is not enabled\n");
return -1;
}
selinux_ctx.enabled = true;
selinux_ctx.enforcing = (security_getenforce() == 1);
printf("SELinux status: %s\n", selinux_ctx.enforcing ? "Enforcing" : "Permissive");
// Initialize file context handle
selinux_ctx.file_contexts = selabel_open(SELABEL_CTX_FILE, NULL, 0);
if (!selinux_ctx.file_contexts) {
perror("selabel_open");
return -1;
}
// Initialize AVC
if (avc_init("selinux_framework", NULL, NULL, NULL, NULL) < 0) {
perror("avc_init");
selabel_close(selinux_ctx.file_contexts);
return -1;
}
printf("SELinux framework initialized\n");
return 0;
}
static void cleanup_selinux_framework(void)
{
if (selinux_ctx.file_contexts) {
selabel_close(selinux_ctx.file_contexts);
}
avc_destroy();
printf("SELinux framework cleanup completed\n");
}
// Test and demonstration functions
static void test_selinux_framework(void)
{
printf("Testing SELinux framework...\n");
// Test context operations
char current_context[MAX_CONTEXT_SIZE];
if (getcon(current_context) == 0) {
printf("Current context: %s\n", current_context);
selinux_context_t ctx;
if (parse_selinux_context(current_context, &ctx) == 0) {
printf("Parsed context - User: %s, Role: %s, Type: %s, Level: %s\n",
ctx.user, ctx.role, ctx.type, ctx.level);
}
}
// Test file access checking
check_file_access("/etc/passwd", "read");
check_file_access("/tmp/test", "write");
// Create and test application profile
app_security_profile_t *profile = create_app_profile("testapp");
if (profile) {
profile->network_client = true;
add_permission_to_profile(profile, "net_bind_service");
add_file_access_to_profile(profile, "/var/lib/testapp", "read");
add_file_access_to_profile(profile, "/var/lib/testapp", "write");
// Generate policy files
FILE *te_file = fopen("testapp.te", "w");
if (te_file) {
generate_type_enforcement_rules(profile, te_file);
fclose(te_file);
printf("Generated testapp.te\n");
}
FILE *fc_file = fopen("testapp.fc", "w");
if (fc_file) {
generate_file_contexts(profile, fc_file);
fclose(fc_file);
printf("Generated testapp.fc\n");
}
destroy_app_profile(profile);
}
// Test audit functions
audit_file_contexts("/tmp");
check_process_compliance();
printf("SELinux framework test completed\n");
}
// Main function
int main(void)
{
if (geteuid() != 0) {
fprintf(stderr, "This program requires root privileges\n");
return 1;
}
if (init_selinux_framework() != 0) {
fprintf(stderr, "Failed to initialize SELinux framework\n");
return 1;
}
test_selinux_framework();
cleanup_selinux_framework();
return 0;
}
This comprehensive Linux security and cryptography programming blog post covers:
- Advanced Cryptographic Framework - Complete implementation with AES-GCM, RSA, ECDSA, secure memory management, and key management
- SELinux Security Module Development - Policy creation, context management, access control, and application security profiles
- Secure System Design - Hardware security modules, secure random generation, and audit frameworks
- Production Security Features - Key derivation, digital signatures, file context management, and compliance checking
The implementation demonstrates enterprise-grade security programming techniques for building hardened applications and security systems.