System vault service
The system_vault
service is a crucial component responsible for robust security management within the OpenBP system. Its primary function is to establish communication with the Hardware Security Module (HSM) through PKCS interfaces. It offers a user-friendly API that enables seamless integration with other services.
By leveraging the capabilities of the HSM and implementing PKCS interfaces, the system_vault
service ensures a high level of security for managing critical information within the OpenBP system. Its user-friendly API further facilitates seamless interaction with other services, making it an essential component for secure and efficient operations.
Seal / Unseal
Upon system startup, the vault enters a sealed
state, which means that communication with the service is not possible. To make effective use of the service, the vault needs to be manually unsealed
using a password. It is crucial to keep this password secure as losing it would render the service inaccessible and result in permanent loss of all stored secrets.
Warning
By default, the service comes with a predefined unsealing password, which it attempts to use during startup. However, it is highly recommended to change this password to enhance security. This can be achieved through appropriate API request within the service.
Usage examples
Info
Those examples are only for external developers. If you are contributor to the OpenBP project, remember to change imports so they are pointing from the inside of the OpenBP repository.
Encrypt/Decrypt arbitrary data
In this example we will encrypt and decrypt string using vaults HSM.
package main
import (
"bytes"
"context"
"fmt"
openbp "github.com/slamy-solutions/openbp-go"
"github.com/slamy-solutions/openbp-go/modules"
"github.com/slamy-solutions/openbp-go/modules/system"
"github.com/slamy-solutions/openbp-go/modules/system/proto/vault"
)
func main() {
ctx := context.TODO()
obp, err := openbp.ConnectToModules(ctx, modules.NewStubConfig().
WithSystemModule(system.NewSystemStubConfig().WithVault()),
)
if err != nil {
panic(err)
}
data := []byte("Hello OpenBP")
// Encrypt data
encryptClient, _ := obp.System.Vault.EncryptStream(ctx)
encryptClient.Send(&vault.EncryptStreamRequest{
PlainData: data,
})
encryptClient.CloseSend()
encryptResponse, _ := encryptClient.Recv()
encryptedData := encryptResponse.EncryptedData
// Decrypt data
decryptClient, _ := obp.System.Vault.DecryptStream(ctx)
decryptClient.Send(&vault.DecryptStreamRequest{
EncryptedData: encryptedData,
})
decryptClient.CloseSend()
decryptResponse, _ := decryptClient.Recv()
// Compare to original data
fmt.Printf("Data restored correctly: %t", bytes.Equal(data, decryptResponse.PlainData))
}
Generate signature (HMAC)
In this example, we will generate HMAC using vaults HSM
package main
import (
"context"
"encoding/base64"
"fmt"
openbp "github.com/slamy-solutions/openbp-go"
"github.com/slamy-solutions/openbp-go/modules"
"github.com/slamy-solutions/openbp-go/modules/system"
"github.com/slamy-solutions/openbp-go/modules/system/proto/vault"
)
func main() {
ctx := context.TODO()
obp, err := openbp.ConnectToModules(ctx, modules.NewStubConfig().
WithSystemModule(system.NewSystemStubConfig().WithVault()),
)
if err != nil {
panic(err)
}
data := []byte("Hello OpenBP")
response, _ := obp.System.Vault.HMACSign(ctx, &vault.HMACSignRequest{
Data: data,
})
signature := base64.URLEncoding.EncodeToString(response.Signature)
fmt.Println("Signature: " + signature)
}
Generate RSA and sign message with it
In this example, we will sign message with RSA key-pair using vaults HSM
package main
import (
"context"
"encoding/base64"
"fmt"
openbp "github.com/slamy-solutions/openbp-go"
"github.com/slamy-solutions/openbp-go/modules"
"github.com/slamy-solutions/openbp-go/modules/system"
"github.com/slamy-solutions/openbp-go/modules/system/proto/vault"
)
func main() {
ctx := context.TODO()
obp, err := openbp.ConnectToModules(ctx, modules.NewStubConfig().
WithSystemModule(system.NewSystemStubConfig().WithVault()),
)
if err != nil {
panic(err)
}
keyName := "my-super-rsa-key-pair"
data := []byte("Hello OpenBP")
obp.System.Vault.EnsureRSAKeyPair(ctx, &vault.EnsureRSAKeyPairRequest{
KeyName: keyName,
})
response, _ := obp.System.Vault.RSASign(ctx, &vault.RSASignRequest{
KeyName: keyName,
Data: data,
})
signature := base64.URLEncoding.EncodeToString(response.Signature)
fmt.Println("Signature: " + signature)
}
Communication API
The system offers communication capabilities with the service through the gRPC interface. The interface definitions, specified in the proto file, are provided by the system
module. This allows clients to interact with the system_vault
service seamlessly using gRPC-based communication protocols.
General
rpc Seal(SealRequest) returns (SealResponse) {};
Close and encrypt vault. After sealing, most of the operations will not be accessible.
The request doesn't have parameters
The response will always be positive, even when the vault is already sealed
rpc Unseal(UnsealRequest) returns (UnsealResponse) {};
Decrypt and open vault. Must be done before most of the operations with vault secrets.
Parameter | Type | Description |
---|---|---|
secret | string | Password to decrypt the vault |
Response value | Type | Description |
---|---|---|
success | bool | Indicates if vault was unsealed or not |
rpc UpdateSealSecret(UpdateSealSecretRequest) returns (UpdateSealSecretResponse) {};
Set up new seal secret and reincrypt vault. The vault must be unsealed before this operation. You don't need to unseal vault after this operation.
This operation requires you to have administrator access to the HSM. Check PKCS11 spec. If you are using emulated HSM (by default) this will be the same as the seal/unseal secret by default. Change it.
Parameter | Type | Description | Default |
---|---|---|---|
currentAdminPassword | string | Current administrator password. | "12345678" |
newPassword | string | New administrator password. | - |
newSecret | string | New seal/unseal secret. | - |
The seal/unseal secret was successfully updated. The administrator password was updated.
Bad administrator password
rpc GetStatus(GetStatusRequest) returns (GetStatusResponse) {};
Get current status of the vault.
The request doesn't have parameters
Response value | Type | Description |
---|---|---|
sealed | bool | Is vault sealed or not |
RSA
The system_vault
service plays a crucial role in securely managing RSA key-pairs. It employs a highly secure approach where the private key is never exposed outside of the Hardware Security Module (HSM) and cannot be extracted from it. On the other hand, the public key, which is intended to be shared and accessible to all, can be retrieved.
Info
To ensure the utmost security, all operations involving the private key are performed exclusively within the HSM. This means that any cryptographic operations, such as signing or decryption, utilize the private key directly within the HSM's protected environment. This approach significantly reduces the risk of private key compromise or unauthorized access.
By securely managing RSA key-pairs within the system_vault
service and relying on the protection provided by the HSM, the confidentiality and integrity of the private key are maintained while allowing the public key to be widely accessible for encryption, verification, or other public operations.
rpc EnsureRSAKeyPair(EnsureRSAKeyPairRequest) returns (EnsureRSAKeyPairResponse) {};
Create RSA key pair if it doesnt exist. The private key never leaves the HSM.
Parameter | Type | Description |
---|---|---|
keyName | string | Unique name of the key-pair |
The key-pair was created or already existed before this operation.
The vault is sealed.
rpc GetRSAPublicKey(GetRSAPublicKeyRequest) returns (GetRSAPublicKeyResponse) {};
Get public key of the RSA key-pair.
Parameter | Type | Description |
---|---|---|
keyName | string | Unique name of the key-pair |
Response value | Type | Description |
---|---|---|
publicKey | bytes | Public key in the PKCS #1, ASN.1 DER format |
Key-pair with provided name doesn't exist
The vault is sealed.
rpc RSASignStream(stream RSASignStreamRequest) returns (RSASignStreamResponse) {};
Sign message stream with RSA private key. It will use SHA512_RSA_PKCS (RS512) algorithm to sign the message.
Tip
If your data is short (maximum several kilobytes) - use RSASign
instead. It will be faster and use less resources.
Parameter | Type | Description |
---|---|---|
keyName | string | Unique name of the key-pair |
data | bytes | Data chunk to sign |
Response value | Type | Description |
---|---|---|
signature | bytes | Signature of the provided data |
Key-pair with provided name doesn't exist
The vault is sealed.
rpc RSAVerifyStream(stream RSAVerifyStreamRequest) returns (RSAVerifyStreamResponse) {};
Validate signature of the message stream using RSA key-pairs public key. It will use SHA512_RSA_PKCS (RS512) algorithm to verify the message.
Tip
If your data is short (maximum several kilobytes) - use RSAVerify
instead. It will be faster and use less resources.
Parameter | Type | Description |
---|---|---|
keyName | string | Unique name of the key-pair |
data | bytes | Data chunk to validate |
signature | bytes | Signature to validate |
Response value | Type | Description |
---|---|---|
valid | bool | True if and only if provided data and its signature matches provided key-pair |
Key-pair with provided name doesn't exist
The vault is sealed.
rpc RSASign(RSASignRequest) returns (RSASignResponse) {};
Sign message with RSA. It will use SHA512_RSA_PKCS (RS512) algorithm to sign the message.
Warning
The data must be short (max several kilobytes). If it is longer - use RSASignStream
instead.
Parameter | Type | Description |
---|---|---|
keyName | string | Unique name of the key-pair |
data | bytes | Data to sign |
Response value | Type | Description |
---|---|---|
signature | bytes | Signature of the provided data |
Key-pair with provided name doesn't exist
The vault is sealed.
rpc RSAVerify(RSAVerifyRequest) returns (RSAVerifyResponse) {};
Validate signature of the message using RSA key-pairs public key. It will use SHA512_RSA_PKCS (RS512) algorithm to verify the message.
Warning
The data must be short (max several kilobytes). If it is longer - use RSAVerifyStream
instead.
Parameter | Type | Description |
---|---|---|
keyName | string | Unique name of the key-pair |
data | bytes | Data to validate |
signature | bytes | Signature to validate |
Response value | Type | Description |
---|---|---|
valid | bool | True if and only if provided data and its signature matches provided key-pair |
Key-pair with provided name doesn't exist
The vault is sealed.
HMAC
The system_vault
service offers the capability to generate HMAC (Hash-based Message Authentication Code) for data. One of the key security measures in this process is that the HMAC secret, which is utilized in generating the HMAC, never leaves the HSM.
Info
To ensure the utmost security, all operations involving HMAC are performed exclusively within the HSM.
rpc HMACSignStream(stream HMACSignStreamRequest) returns (HMACSignStreamResponse) {};
Calculate HMAC signature for input data stream. HMAC secret never leaves the HSM (hardware security module). It automatically uses the best available HMAC algorithm for currently used HSM.
Tip
If your data is short (maximum several kilobytes) - use HMACSign
instead. It will be faster and use less resources.
Parameter | Type | Description |
---|---|---|
data | bytes | Data chunk to sign |
Response value | Type | Description |
---|---|---|
signature | bytes | Signature of the provided data |
The vault is sealed.
rpc HMACVerifyStream(stream HMACVerifyStreamRequest) returns (HMACVerifyStreamResponse) {};
Verify HMAC signature of the data stream.
Tip
If your data is short (maximum several kilobytes) - use HMACVerify
instead. It will be faster and use less resources.
Parameter | Type | Description |
---|---|---|
data | bytes | Data chunk to validate |
signature | bytes | Signature to validate |
Response value | Type | Description |
---|---|---|
valid | bool | True if and only if provided data and its signature matches |
The vault is sealed.
rpc HMACSign(HMACSignRequest) returns (HMACSignResponse) {};
Calculate HMAC signature for input data. HMAC secret never leaves the HSM (hardware security module). It automatically uses the best available HMAC algorithm for currently used HSM.
Warning
The data must be short (max several kilobytes). If it is longer - use HMACSignStream
instead.
Parameter | Type | Description |
---|---|---|
data | bytes | Data to sign |
Response value | Type | Description |
---|---|---|
signature | bytes | Signature of the provided data |
The vault is sealed.
rpc HMACVerify(HMACVerifyRequest) returns (HMACVerifyResponse) {};
Verifiy HMAC signature of the data.
Warning
The data must be short (max several kilobytes). If it is longer - use HMACVerifyStream
instead.
Parameter | Type | Description |
---|---|---|
data | bytes | Data to validate |
signature | bytes | Signature to validate |
Response value | Type | Description |
---|---|---|
valid | bool | True if and only if provided data and its signature matches |
The vault is sealed.
Encryption
The system_vault
service includes the capability to encrypt data, adding an extra layer of security to sensitive information. The encryption key used for this process is securely managed and protected within the HSM, safeguarding it from potential threats.
rpc HMACSignStream(stream HMACSignStreamRequest) returns (HMACSignStreamResponse) {};
Encrypt data stream. Encryption secret never leaves the HSM (hardware security module). It automatically uses the best available encryption algorithm for currently used HSM. It will only select the algorithm that is capable of decrypting from the middle of the whole data (partial decryption).
Tip
If your data is short (maximum several kilobytes) - use HMACSign
instead. It will be faster and use less resources.
Parameter | Type | Description |
---|---|---|
plainData | bytes | Data chunk to encrypt |
Response value | Type | Description |
---|---|---|
encryptedData | bytes | Encrypted chunk of data |
The vault is sealed.
rpc HMACVerifyStream(stream HMACVerifyStreamRequest) returns (HMACVerifyStreamResponse) {};
Decrypt data stream. If you want to decrypt part of the information from the middle of the whole data - ensure, that the first chunk of the data, that you are sending is padded by 2048 bit.
Tip
If your data is short (maximum several kilobytes) - use HMACVerify
instead. It will be faster and use less resources.
Parameter | Type | Description |
---|---|---|
encryptedData | bytes | Encrypted chunk of the data |
Response value | Type | Description |
---|---|---|
plainData | bytes | Decrypted chunk of the data |
The vault is sealed.
HSM
The system_vault service offers the flexibility to work with multiple Hardware Security Module (HSM) providers, allowing users to configure their preferred provider before the initial startup of the system. This capability enables seamless integration with different HSM technologies based on specific requirements or preferences.
To select a particular HSM provider, you can set the HSM_PROVIDER
environment variable. The following providers are currently supported:
softhsm2
: This is the default provider that emulates an HSM using the SoftHSM2 library.dynamic
: This provider offers a dynamic interface, allowing potential connections with various PKCS11 client libraries. It provides flexibility for utilizing different HSM implementations.
Warning
It is worth mentioning that due to the nature of making secrets non-extractable for security reasons, switching HSM providers at runtime may not be possible. Therefore, it is recommended to configure the desired provider before the initial startup of the system.
Furthermore, the system is designed to accommodate additional HSM providers in the future. Contributions to expand the range of supported providers are highly appreciated, ensuring ongoing enhancement and versatility in choosing the most suitable HSM solution.
SoftHSM2
The SoftHSM2 provider does not require any additional configuration. It comes preconfigured with optimal settings that adhere to best practices, alleviating any concerns or need for manual adjustments on your part.
Dynamic HSM provider
To ensure the proper functioning of the dynamic provider, you need to follow a few steps. First, run OpenBP and it will create a volume for the system_vault
service at ./data/system/vault/
pkcs (depending on what setup you are using). In this folder, copy your PKCS11 library and name it pkcs.so
.
Additionally, you need to define the slot by setting the DYNAMIC_PKCS11_SLOT
environment variable. This variable specifies the slot that the service should attempt to open when loading the PKCS11 library.
By configuring the environment variable and placing the PKCS11 library in the designated folder, the system_vault
service will automatically load the library and try to open the provided slot during its startup process.
Start OpenBP and check the logs. You will receive a message if everything is ok.