Skip to content

Commit

Permalink
Merge pull request #442 from nix-community/signing
Browse files Browse the repository at this point in the history
move crypt_sign_detached out of libnixstore to harmonia
  • Loading branch information
Mic92 authored Nov 3, 2024
2 parents e11a4a3 + 9e05139 commit 180476d
Show file tree
Hide file tree
Showing 14 changed files with 49 additions and 51 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions harmonia/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ url = "2.4.1"


libnixstore = { path = "../libnixstore" }

[build-dependencies]
pkg-config = "0.3"
3 changes: 3 additions & 0 deletions harmonia/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
pkg_config::probe_library("libsodium").unwrap();
}
12 changes: 8 additions & 4 deletions harmonia/src/narlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ use std::collections::HashMap;
use std::path::PathBuf;
use tokio::fs::symlink_metadata;

fn is_false(b: &bool) -> bool {
!b
}

#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
#[serde(tag = "type")]
enum NarEntry {
Expand All @@ -24,7 +28,8 @@ enum NarEntry {
#[serde(rename = "narOffset")]
nar_offset: Option<u64>,
size: u64,
#[serde(default)]

#[serde(default, skip_serializing_if = "is_false")]
executable: bool,
},
#[serde(rename = "symlink")]
Expand Down Expand Up @@ -236,17 +241,16 @@ mod test {
.unwrap();
let parsed_json: serde_json::Value = serde_json::from_slice(&res2.stdout).unwrap();
let pretty_string = serde_json::to_string_pretty(&parsed_json).unwrap();
println!("{}", pretty_string);
assert!(res2.status.success());
let mut reference_json: NarEntry = serde_json::from_str(&pretty_string).unwrap();

// our posix implementation does not support narOffset
unset_nar_offset(&mut reference_json);

println!("get_nar_list:");
println!("{:?}", json.root);
println!("{}", serde_json::to_string_pretty(&json.root).unwrap());
println!("nix nar ls --json --recursive:");
println!("{:?}", reference_json);
println!("{}", pretty_string);
assert_eq!(json.root, reference_json);

Ok(())
Expand Down
26 changes: 24 additions & 2 deletions harmonia/src/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ use crate::config::SigningKey;
// omitted: E O U T
const BASE32_CHARS: &[u8] = b"0123456789abcdfghijklmnpqrsvwxyz";

#[link(name = "sodium")]
extern "C" {
fn crypto_sign_detached(
sig: *mut u8,
sig_len: *mut usize,
msg: *const u8,
msg_len: usize,
sk: *const u8,
) -> i32;
}

/// Converts the given byte slice to a nix-compatible base32 encoded String.
fn to_nix_base32(bytes: &[u8]) -> String {
let len = (bytes.len() * 8 - 1) / 5 + 1;
Expand Down Expand Up @@ -127,8 +138,19 @@ pub(crate) fn fingerprint_path(
}

pub(crate) fn sign_string(sign_key: &SigningKey, msg: &str) -> String {
let signature = libnixstore::sign_detached(&sign_key.key, msg);
let base64 = general_purpose::STANDARD.encode(signature);
let mut signature = vec![0u8; 64]; // crypto_sign_BYTES -> 64
let mut signature_len: usize = 0;
let msg = msg.as_bytes();
unsafe {
crypto_sign_detached(
signature.as_mut_ptr(),
&mut signature_len,
msg.as_ptr(),
msg.len(),
sign_key.key.as_ptr(),
)
};
let base64 = general_purpose::STANDARD.encode(&signature[..signature_len]);
format!("{}:{}", sign_key.name, base64)
}

Expand Down
11 changes: 3 additions & 8 deletions libnixstore/README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
# libnixstore

Is a library that provides simple access to your local nix store, based on c++
bindings. It mimics the already available perl bindings but also adds bindings
on top, that might be useful.
These are libnix bindings required by harmonia to communicate with the local nix daemon.
Over time we will replace the dependencies on libnix with rust-native code.

Note: This project provides bindings, this makes the project automatically unsafe.

Supported nix version:
- nix 2.8
- nix 2.9
- nix 2.10
- nix 2.11
- nix 2.24

## Requirements

Expand All @@ -26,7 +22,6 @@ stdenv.mkDerivation {
# required
nix
nlohmann_json
libsodium
boost
# additional packages you might need
Expand Down
1 change: 0 additions & 1 deletion libnixstore/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ fn main() {

pkg_config::probe_library("nix-store").unwrap();
pkg_config::probe_library("nix-main").unwrap();
pkg_config::probe_library("libsodium").unwrap();

let includedir =
pkg_config::get_variable("nix-store", "includedir").expect("Failed to get includedir");
Expand Down
2 changes: 0 additions & 2 deletions libnixstore/include/nix.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ rust::String query_path_hash(rust::Str path);
InternalPathInfo query_path_info(rust::Str path, bool base32);
rust::String query_path_from_hash_part(rust::Str hash_part);
rust::String sign_string(rust::Str secret_key, rust::Str msg);
rust::Vec<unsigned char>
sign_detached(rust::Slice<const unsigned char> secret_key, rust::Str msg);
rust::String get_store_dir();
rust::String get_real_store_dir();
rust::String get_build_log(rust::Str derivation_path);
Expand Down
7 changes: 0 additions & 7 deletions libnixstore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ mod ffi {
fn query_path_hash(path: &str) -> Result<String>;
fn query_path_info(path: &str, base32: bool) -> Result<InternalPathInfo>;
fn query_path_from_hash_part(hash_part: &str) -> Result<String>;
fn sign_detached(secret_key: &[u8], msg: &str) -> Vec<u8>;
fn get_store_dir() -> String;
fn get_real_store_dir() -> String;
fn get_build_log(derivation_path: &str) -> Result<String>;
Expand Down Expand Up @@ -129,12 +128,6 @@ pub fn query_path_from_hash_part(hash_part: &str) -> Option<String> {
}
}

#[inline]
/// Return a detached signature of the given string.
pub fn sign_detached(secret_key: &[u8], msg: &str) -> Vec<u8> {
ffi::sign_detached(secret_key, msg)
}

#[inline]
#[must_use]
/// Returns the path to the directory where nix store sources and derived files.
Expand Down
17 changes: 0 additions & 17 deletions libnixstore/src/nix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include <nix/nar-accessor.hh>

#include <nlohmann/json.hpp>
#include <sodium.h>

#include <stdlib.h>

Expand Down Expand Up @@ -127,22 +126,6 @@ rust::String query_path_from_hash_part(rust::Str hash_part) {
get_store()->queryPathFromHashPart(STRING_VIEW(hash_part)));
}

rust::Vec<unsigned char>
sign_detached(rust::Slice<const unsigned char> secret_key, rust::Str msg) {
rust::Vec<unsigned char> sig;
sig.reserve(crypto_sign_BYTES);
unsigned long long sigLen;
for (size_t i = 0; i < crypto_sign_BYTES; i++) {
sig.push_back(0);
}

crypto_sign_detached(sig.data(), &sigLen, (unsigned char *)msg.data(),
msg.size(), (unsigned char *)secret_key.data());
sig.truncate(sigLen);

return sig;
}

rust::String get_store_dir() {
return nix::settings.nixStore;
}
Expand Down
11 changes: 4 additions & 7 deletions tests/lib.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ test:
pkgs ? import <nixpkgs> { },
...
}@args:
let
inherit (pkgs) lib;
nixos-lib = import (pkgs.path + "/nixos/lib") { };
in
(nixos-lib.runTest {
hostPkgs = pkgs;
(pkgs.testers.runNixOSTest {
# speed-up evaluation
defaults.documentation.enable = lib.mkDefault false;
defaults.documentation.enable = pkgs.lib.mkDefault false;
# Faster dhcp
defaults.networking.useNetworkd = pkgs.lib.mkDefault true;
# to accept external dependencies such as disko
node.specialArgs.inputs = args;
imports = [ test ];
Expand Down
2 changes: 1 addition & 1 deletion tests/t00-simple.nix
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
import json
start_all()
client01.wait_until_succeeds("curl -f http://harmonia:5000/version")
client01.wait_until_succeeds("timeout 1 curl -f http://harmonia:5000")
client01.succeed("curl -f http://harmonia:5000/nix-cache-info")
client01.wait_until_succeeds("nix copy --from http://harmonia:5000/ ${pkgs.hello}")
Expand Down
2 changes: 1 addition & 1 deletion tests/t02-varnish.nix
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
testScript = ''
start_all()
client01.wait_until_succeeds("curl -f http://harmonia/version")
client01.wait_until_succeeds("timeout 1 curl -f http://harmonia/version")
client01.succeed("curl -f http://harmonia/nix-cache-info")
client01.wait_until_succeeds("nix copy --from http://harmonia/ ${pkgs.hello}")
Expand Down
2 changes: 1 addition & 1 deletion tests/t03-chroot.nix
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
harmonia.systemctl("start harmonia-dev.service")
harmonia.wait_for_unit("harmonia-dev.service")
client01.wait_until_succeeds("curl -f http://harmonia:5000/version")
client01.wait_until_succeeds("timeout 1 curl -f http://harmonia:5000/version")
client01.succeed("curl -f http://harmonia:5000/nix-cache-info")
client01.wait_until_succeeds(f"nix copy --from http://harmonia:5000/ {f}")
Expand Down

0 comments on commit 180476d

Please sign in to comment.