Skip to content

Commit

Permalink
feat: clustering support
Browse files Browse the repository at this point in the history
You can now add multiple NetHSM instances in a "slot", the module will
use the instances in a round-robin fashion and will failover to another
instance if one sends a 412 or 5xx error.
  • Loading branch information
nponsard committed Jul 27, 2023
1 parent f1f8b46 commit fb2b97e
Show file tree
Hide file tree
Showing 14 changed files with 596 additions and 320 deletions.
5 changes: 3 additions & 2 deletions container/nginx/p11nethsm.conf
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
slots:
- label: LocalHSM
description: Local HSM (docker)
url: "https://192.168.3.161:8443/api/v1"
operator:
username: "operator"
# password: "opPassphrase"
danger_insecure_cert: true
instances:
- url: "https://192.168.3.161:8443/api/v1"
danger_insecure_cert: true
32 changes: 13 additions & 19 deletions p11nethsm.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,22 @@ slots:
# password: "env:NETHSM_PASS" # operator password
- label: LocalHSM
description: Local HSM (docker)
url: "https://localhost:8443/api/v1"
operator:
username: "operator"
password: "opPassphrase"
administrator:
username: "admin"
password: "Administrator"
danger_insecure_cert: true
# certificate: |
# -----BEGIN CERTIFICATE-----
# MIIBHjCBxaADAgECAgkApoJ3bQqnwmcwCgYIKoZIzj0EAwIwFDESMBAGA1UEAwwJ
# a2V5ZmVuZGVyMCAXDTcwMDEwMTAwMDAwMFoYDzk5OTkxMjMxMjM1OTU5WjAUMRIw
# EAYDVQQDDAlrZXlmZW5kZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARzywjh
# NQM4pBxNBIOrgWvKFcWle5SLGux1caV9rur/fnPptDnekjZ2fajJX2EEACjk9JKw
# VykkfhbAdR46VGgFMAoGCCqGSM49BAMCA0gAMEUCIQDvm9J5y9S9POsfdlo5lKzg
# VFYo7UBT3aTavB6b+hUUbQIgMzT1fBhbBFTgCx5LKQMp1V7SuyCby3oxL5RWYqhl
# /R0=
# -----END CERTIFICATE-----

# - label: LocalHSM
# description: Local HSM (docker)
# url: "https://localhost:8443/api/v1"
# user: "admin"
# password: "Administrator"
# danger_insecure_cert: true
instances:
- url: "https://localhost:8443/api/v1"
danger_insecure_cert: true
# certificate: |
# -----BEGIN CERTIFICATE-----
# MIIBHjCBxaADAgECAgkApoJ3bQqnwmcwCgYIKoZIzj0EAwIwFDESMBAGA1UEAwwJ
# a2V5ZmVuZGVyMCAXDTcwMDEwMTAwMDAwMFoYDzk5OTkxMjMxMjM1OTU5WjAUMRIw
# EAYDVQQDDAlrZXlmZW5kZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARzywjh
# NQM4pBxNBIOrgWvKFcWle5SLGux1caV9rur/fnPptDnekjZ2fajJX2EEACjk9JKw
# VykkfhbAdR46VGgFMAoGCCqGSM49BAMCA0gAMEUCIQDvm9J5y9S9POsfdlo5lKzg
# VFYo7UBT3aTavB6b+hUUbQIgMzT1fBhbBFTgCx5LKQMp1V7SuyCby3oxL5RWYqhl
# /R0=
# -----END CERTIFICATE-----
33 changes: 19 additions & 14 deletions pkcs11/src/api/generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,22 +223,27 @@ pub extern "C" fn C_GenerateRandom(
}
lock_session!(hSession, session);

let api_config = match session.login_ctx.operator() {
Some(conf) => conf,
None => {
error!(
"C_GenerateRandom() called with session not connected as operator {}.",
hSession
);
return cryptoki_sys::CKR_USER_NOT_LOGGED_IN;
}
};
if !session
.login_ctx
.can_run_mode(crate::backend::login::UserMode::Operator)
{
error!(
"C_GenerateRandom() called with session not connected as operator {}.",
hSession
);
return cryptoki_sys::CKR_USER_NOT_LOGGED_IN;
}

let data = match default_api::random_post(
&api_config,
openapi::models::RandomRequestData {
length: ulRandomLen as i32,
let data = match session.login_ctx.try_(
|api_config| {
default_api::random_post(
&api_config,
openapi::models::RandomRequestData {
length: ulRandomLen as i32,
},
)
},
crate::backend::login::UserMode::Operator,
) {
Ok(data) => data,
Err(e) => {
Expand Down
41 changes: 11 additions & 30 deletions pkcs11/src/api/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use cryptoki_sys::CKR_OK;
use log::{error, trace};
use openapi::apis::default_api;

use crate::{lock_mutex, lock_session};

Expand Down Expand Up @@ -50,34 +49,16 @@ pub extern "C" fn C_SetPIN(
return cryptoki_sys::CKR_PIN_INCORRECT;
}

let login_ctx = session.login_ctx.operator();
let api_config = match login_ctx.as_ref() {
Some(conf) => conf,
None => {
error!(
"C_SetPIN() called with session not connected as operator {}.",
hSession
);
return cryptoki_sys::CKR_USER_NOT_LOGGED_IN;
}
};

let user_id = match api_config.basic_auth.as_ref() {
Some(basic_auth) => basic_auth.0.clone(),
None => return cryptoki_sys::CKR_GENERAL_ERROR,
};

match default_api::users_user_id_passphrase_post(
api_config,
&user_id,
openapi::models::UserPassphrasePostData {
passphrase: new_pin.to_string(),
},
) {
Ok(_) => cryptoki_sys::CKR_OK,
Err(err) => {
error!("Failed to set new pin: {:?}", err);
cryptoki_sys::CKR_GENERAL_ERROR
}
if !session
.login_ctx
.can_run_mode(crate::backend::login::UserMode::OperatorOrAdministrator)
{
error!(
"C_SetPIN() called with session not connected as operator {}.",
hSession
);
return cryptoki_sys::CKR_USER_NOT_LOGGED_IN;
}

session.login_ctx.change_pin(new_pin.to_string())
}
29 changes: 24 additions & 5 deletions pkcs11/src/api/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use cryptoki_sys::{
CK_TOKEN_INFO, CK_ULONG,
};
use log::{debug, error, trace};
use openapi::models::SystemState;
use openapi::{apis::default_api, models::SystemState};

use crate::{
backend::slot::get_slot,
backend::{login::LoginCtx, slot::get_slot},
data::DEVICE,
defs::{DEFAULT_FIRMWARE_VERSION, DEFAULT_HARDWARE_VERSION, MECHANISM_LIST},
lock_mutex, lock_session, padded_str,
Expand Down Expand Up @@ -79,19 +79,31 @@ pub extern "C" fn C_GetSlotInfo(

let mut flags = 0;

let mut login_ctx = LoginCtx::new(None, None, slot.instances.clone());

let result = login_ctx.try_(
|conf| default_api::info_get(conf),
crate::backend::login::UserMode::Guest,
);

// fetch info from the device

let info = match openapi::apis::default_api::info_get(&slot.api_config) {
let info = match result {
Ok(info) => info,
Err(e) => {
error!("Error getting info: {:?}", e);
return cryptoki_sys::CKR_FUNCTION_FAILED;
}
};

let result = login_ctx.try_(
|conf| default_api::health_state_get(conf),
crate::backend::login::UserMode::Guest,
);

// fetch the sysem state

let system_state = match openapi::apis::default_api::health_state_get(&slot.api_config) {
let system_state = match result {
Ok(info) => info,
Err(e) => {
error!("Error getting system state: {:?}", e);
Expand Down Expand Up @@ -135,9 +147,16 @@ pub extern "C" fn C_GetTokenInfo(
return cryptoki_sys::CKR_ARGUMENTS_BAD;
}

let mut login_ctx = LoginCtx::new(None, None, slot.instances.clone());

let result = login_ctx.try_(
|conf| default_api::info_get(conf),
crate::backend::login::UserMode::Guest,
);

// fetch info from the device

let info = match openapi::apis::default_api::info_get(&slot.api_config) {
let info = match result {
Ok(info) => info,
Err(e) => {
error!("Error getting info: {:?}", e);
Expand Down
57 changes: 35 additions & 22 deletions pkcs11/src/backend/decrypt.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use base64::{engine::general_purpose, Engine};
use cryptoki_sys::{CKR_ARGUMENTS_BAD, CKR_DEVICE_ERROR, CKR_MECHANISM_INVALID, CK_RV};
use cryptoki_sys::{
CKR_ARGUMENTS_BAD, CKR_DEVICE_ERROR, CKR_MECHANISM_INVALID, CKR_USER_NOT_LOGGED_IN, CK_RV,
};
use log::{error, trace};
use openapi::apis::default_api;

use super::{
db::Object,
login::{self, LoginCtx},
mechanism::{MechMode, Mechanism},
};

Expand All @@ -13,15 +16,18 @@ pub struct DecryptCtx {
pub mechanism: Mechanism,
pub key_id: String,
pub data: Vec<u8>,
api_config: openapi::apis::configuration::Configuration,
login_ctx: LoginCtx,
}

impl DecryptCtx {
pub fn init(
mechanism: Mechanism,
key: &Object,
api_config: openapi::apis::configuration::Configuration,
) -> Result<Self, CK_RV> {
pub fn init(mechanism: Mechanism, key: &Object, login_ctx: &LoginCtx) -> Result<Self, CK_RV> {
let login_ctx = login_ctx.clone();

if login_ctx.can_run_mode(login::UserMode::Operator) {
error!("No operator is logged in");
return Err(CKR_USER_NOT_LOGGED_IN);
}

let api_mech = match mechanism.to_api_mech(MechMode::Decrypt) {
Some(mech) => mech,
None => {
Expand All @@ -45,14 +51,14 @@ impl DecryptCtx {
mechanism,
key_id: key.id.clone(),
data: Vec::new(),
api_config,
login_ctx,
})
}
pub fn update(&mut self, data: &[u8]) {
self.data.extend_from_slice(data);
}

pub fn decrypt_final(&self) -> Result<Vec<u8>, cryptoki_sys::CK_RV> {
pub fn decrypt_final(&mut self) -> Result<Vec<u8>, cryptoki_sys::CK_RV> {
let b64_message = general_purpose::STANDARD.encode(self.data.as_slice());

let mode = self.mechanism.decrypt_name().ok_or(CKR_ARGUMENTS_BAD)?;
Expand All @@ -63,19 +69,26 @@ impl DecryptCtx {
.iv()
.map(|iv| general_purpose::STANDARD.encode(iv.as_slice()));

let output = default_api::keys_key_id_decrypt_post(
&self.api_config,
&self.key_id,
openapi::models::DecryptRequestData {
mode,
encrypted: b64_message,
iv,
},
)
.map_err(|err| {
error!("Failed to decrypt: {:?}", err);
CKR_DEVICE_ERROR
})?;
let output = self
.login_ctx
.try_(
|api_config| {
default_api::keys_key_id_decrypt_post(
api_config,
&self.key_id,
openapi::models::DecryptRequestData {
mode,
encrypted: b64_message,
iv,
},
)
},
login::UserMode::Operator,
)
.map_err(|err| {
error!("Failed to decrypt: {:?}", err);
CKR_DEVICE_ERROR
})?;

general_purpose::STANDARD
.decode(output.decrypted)
Expand Down
Loading

0 comments on commit fb2b97e

Please sign in to comment.