void tls_crypt_v2_write_client_key_file(const char *filename, const char *b64_metadata, const char *server_key_file, const char *server_key_inline) { struct gc_arena gc = gc_new(); struct key_ctx server_key = { 0 }; struct buffer client_key_pem = { 0 }; struct buffer dst = alloc_buf_gc(TLS_CRYPT_V2_CLIENT_KEY_LEN + TLS_CRYPT_V2_MAX_WKC_LEN, &gc); struct key2 client_key = { 2 }; if (!rand_bytes((void *)client_key.keys, sizeof(client_key.keys))) { msg(M_FATAL, "ERROR: could not generate random key"); goto cleanup; } ASSERT(buf_write(&dst, client_key.keys, sizeof(client_key.keys))); struct buffer metadata = alloc_buf_gc(TLS_CRYPT_V2_MAX_METADATA_LEN, &gc); if (b64_metadata) { if (TLS_CRYPT_V2_MAX_B64_METADATA_LEN < strlen(b64_metadata)) { msg(M_FATAL, "ERROR: metadata too long (%d bytes, max %u bytes)", (int)strlen(b64_metadata), TLS_CRYPT_V2_MAX_B64_METADATA_LEN); } ASSERT(buf_write(&metadata, &TLS_CRYPT_METADATA_TYPE_USER, 1)); int decoded_len = openvpn_base64_decode(b64_metadata, BPTR(&metadata), BCAP(&metadata)); if (decoded_len < 0) { msg(M_FATAL, "ERROR: failed to base64 decode provided metadata"); goto cleanup; } ASSERT(buf_inc_len(&metadata, decoded_len)); } else { int64_t timestamp = htonll((uint64_t)now); ASSERT(buf_write(&metadata, &TLS_CRYPT_METADATA_TYPE_TIMESTAMP, 1)); ASSERT(buf_write(&metadata, ×tamp, sizeof(timestamp))); } tls_crypt_v2_init_server_key(&server_key, true, server_key_file, server_key_inline); if (!tls_crypt_v2_wrap_client_key(&dst, &client_key, &metadata, &server_key, &gc)) { msg(M_FATAL, "ERROR: could not wrap generated client key"); goto cleanup; } /* PEM-encode Kc || WKc */ if (!crypto_pem_encode(tls_crypt_v2_cli_pem_name, &client_key_pem, &dst, &gc)) { msg(M_FATAL, "ERROR: could not PEM-encode client key"); goto cleanup; } if (!buffer_write_file(filename, &client_key_pem)) { msg(M_FATAL, "ERROR: could not write client key file"); goto cleanup; } /* Sanity check: load client key (as "client") */ struct key_ctx_bi test_client_key; struct buffer test_wrapped_client_key; msg(D_GENKEY, "Testing client-side key loading..."); tls_crypt_v2_init_client_key(&test_client_key, &test_wrapped_client_key, filename, NULL); free_key_ctx_bi(&test_client_key); /* Sanity check: unwrap and load client key (as "server") */ struct buffer test_metadata = alloc_buf_gc(TLS_CRYPT_V2_MAX_METADATA_LEN, &gc); struct key2 test_client_key2 = { 0 }; free_key_ctx(&server_key); tls_crypt_v2_init_server_key(&server_key, false, server_key_file, server_key_inline); msg(D_GENKEY, "Testing server-side key loading..."); ASSERT(tls_crypt_v2_unwrap_client_key(&test_client_key2, &test_metadata, test_wrapped_client_key, &server_key)); secure_memzero(&test_client_key2, sizeof(test_client_key2)); free_buf(&test_wrapped_client_key); cleanup: secure_memzero(&client_key, sizeof(client_key)); free_key_ctx(&server_key); buf_clear(&client_key_pem); buf_clear(&dst); gc_free(&gc); }
void free_key_ctx_bi (struct key_ctx_bi *ctx) { free_key_ctx(&ctx->encrypt); free_key_ctx(&ctx->decrypt); }