Skip to content

Commit 10b0c16

Browse files
committed
feat: add signature verification with a submitted public key
Signed-off-by: Michele Meloni <[email protected]>
1 parent 6de3f9d commit 10b0c16

File tree

23 files changed

+312
-33
lines changed

23 files changed

+312
-33
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ Environment variables:
336336
IMMUCLIENT_PKEY=./tools/mtls/4_client/private/localhost.key.pem
337337
IMMUCLIENT_CERTIFICATE=./tools/mtls/4_client/certs/localhost.cert.pem
338338
IMMUCLIENT_CLIENTCAS=./tools/mtls/2_intermediate/certs/ca-chain.cert.pem
339+
IMMUCLIENT_PUBLIC_KEY=
339340

340341
IMPORTANT: All get and safeget functions return base64-encoded keys and values, while all set and safeset functions expect base64-encoded inputs.
341342

cmd/immuadmin/command/login_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package immuadmin
1919
import (
2020
"bytes"
2121
"context"
22+
"github.com/stretchr/testify/require"
2223
"io/ioutil"
2324
"os"
2425
"testing"

cmd/immuclient/audit/auditagent.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,16 @@ func options() *client.Options {
171171
prometheusPort := viper.GetString("prometheus-port")
172172
prometheusHost := viper.GetString("prometheus-host")
173173
logfilename := viper.GetString("logfile")
174+
publicKey := viper.GetString("public-key")
174175
options := client.DefaultOptions().
175176
WithPort(port).
176177
WithAddress(address).
177178
WithTokenFileName(tokenFileName).
178179
WithMTLs(mtls).WithPidPath(pidpath).
179180
WithPrometheusPort(prometheusPort).
180181
WithPrometheusHost(prometheusHost).
181-
WithLogFileName(logfilename)
182+
WithLogFileName(logfilename).
183+
WithPublicKey(publicKey)
182184
if mtls {
183185
// todo https://golang.org/src/crypto/x509/root_linux.go
184186
options.MTLsOptions = client.DefaultMTLsOptions().

cmd/immuclient/audit/auditor.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ package audit
1818

1919
import (
2020
"context"
21+
"crypto/ecdsa"
2122
"errors"
2223
"fmt"
24+
"github.com/codenotary/immudb/pkg/signer"
2325
"os"
2426
"path/filepath"
2527
"strconv"
@@ -101,13 +103,23 @@ func (cAgent *auditAgent) InitAgent() (AuditAgent, error) {
101103
return nil, fmt.Errorf("Invalid login operation: %v", err)
102104
}
103105
}
106+
107+
var pk *ecdsa.PublicKey
108+
if cliOpts.PublicKey != "" {
109+
pk, err = signer.ParsePublicKeyFile(cliOpts.PublicKey)
110+
if err != nil {
111+
return nil, err
112+
}
113+
}
114+
104115
cAgent.ImmuAudit, err = auditor.DefaultAuditor(time.Duration(cAgent.cycleFrequency)*time.Second,
105116
fmt.Sprintf("%s:%v", options().Address, options().Port),
106117
cliOpts.DialOptions,
107118
auditUsername,
108119
auditPassword,
109120
auditDatabases,
110121
auditSignature,
122+
pk,
111123
auditor.AuditNotificationConfig{
112124
URL: auditNotificationURL,
113125
Username: auditNotificationUsername,

cmd/immuclient/command/init.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ func (cl *commandline) configureFlags(cmd *cobra.Command) error {
5353
cmd.PersistentFlags().String("audit-notification-url", "", "If set, auditor will send a POST request at this URL with audit result details.")
5454
cmd.PersistentFlags().String("audit-notification-username", "", "Username used to authenticate when publishing audit result to 'audit-notification-url'.")
5555
cmd.PersistentFlags().String("audit-notification-password", "", "Password used to authenticate when publishing audit result to 'audit-notification-url'.")
56+
cmd.PersistentFlags().String("public-key", "", "Path to the public key to verify signatures when presents")
5657

5758
viper.BindPFlag("immudb-port", cmd.PersistentFlags().Lookup("immudb-port"))
5859
viper.BindPFlag("immudb-address", cmd.PersistentFlags().Lookup("immudb-address"))
@@ -75,6 +76,7 @@ func (cl *commandline) configureFlags(cmd *cobra.Command) error {
7576
viper.BindPFlag("audit-notification-url", cmd.PersistentFlags().Lookup("audit-notification-url"))
7677
viper.BindPFlag("audit-notification-username", cmd.PersistentFlags().Lookup("audit-notification-username"))
7778
viper.BindPFlag("audit-notification-password", cmd.PersistentFlags().Lookup("audit-notification-password"))
79+
viper.BindPFlag("public-key", cmd.PersistentFlags().Lookup("public-key"))
7880

7981
viper.SetDefault("immudb-port", client.DefaultOptions().Port)
8082
viper.SetDefault("immudb-address", client.DefaultOptions().Address)
@@ -96,6 +98,7 @@ func (cl *commandline) configureFlags(cmd *cobra.Command) error {
9698
viper.SetDefault("audit-notification-url", "")
9799
viper.SetDefault("audit-notification-username", "")
98100
viper.SetDefault("audit-notification-password", "")
101+
viper.SetDefault("public-key", "")
99102
viper.SetDefault("dir", os.TempDir())
100103
return nil
101104
}

cmd/immuclient/command/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Environment variables:
3737
IMMUCLIENT_PKEY=./tools/mtls/4_client/private/localhost.key.pem
3838
IMMUCLIENT_CERTIFICATE=./tools/mtls/4_client/certs/localhost.cert.pem
3939
IMMUCLIENT_CLIENTCAS=./tools/mtls/2_intermediate/certs/ca-chain.cert.pem
40+
IMMUCLIENT_PUBLIC_KEY=
4041
4142
IMPORTANT: All get and safeget functions return base64-encoded keys and values, while all set and safeset functions expect base64-encoded inputs.`,
4243
DisableAutoGenTag: true,

cmd/immuclient/immuc/init.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ func Options() *client.Options {
117117
WithAddress(viper.GetString("immudb-address")).
118118
WithTokenFileName(viper.GetString("tokenfile")).
119119
WithMTLs(viper.GetBool("mtls")).
120-
WithTokenService(client.NewTokenService().WithTokenFileName(viper.GetString("tokenfile")).WithHds(client.NewHomedirService()))
120+
WithTokenService(client.NewTokenService().WithTokenFileName(viper.GetString("tokenfile")).WithHds(client.NewHomedirService())).
121+
WithPublicKey(viper.GetString("public-key"))
121122

122123
if viper.GetBool("mtls") {
123124
// todo https://golang.org/src/crypto/x509/root_linux.go

configs/immuclient.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ pkey = "./tools/mtls/4_client/private/localhost.key.pem"
88
certificate = "./tools/mtls/4_client/certs/localhost.cert.pem"
99
clientcas = "./tools/mtls/2_intermediate/certs/ca-chain.cert.pem"
1010
audit-signature = "ignore"
11+
public-key = "" #used to verify signatures

pkg/api/schema/state.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ limitations under the License.
1616
package schema
1717

1818
import (
19+
"crypto/ecdsa"
1920
"crypto/sha256"
2021
"encoding/binary"
2122
"errors"
@@ -30,14 +31,10 @@ func (state *ImmutableState) ToBytes() []byte {
3031
return b
3132
}
3233

33-
//CheckSignature
34-
func (state *ImmutableState) CheckSignature() (ok bool, err error) {
34+
// CheckSignature
35+
func (state *ImmutableState) CheckSignature(key *ecdsa.PublicKey) (ok bool, err error) {
3536
if state.Signature == nil {
3637
return false, errors.New("no signature found")
3738
}
38-
if state.Signature.PublicKey == nil {
39-
return false, errors.New("no public key found")
40-
}
41-
42-
return signer.Verify(state.ToBytes(), state.Signature.Signature, state.Signature.PublicKey)
39+
return signer.Verify(state.ToBytes(), state.Signature.Signature, key)
4340
}

pkg/client/auditor/auditor.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package auditor
1919
import (
2020
"bytes"
2121
"context"
22+
"crypto/ecdsa"
2223
"encoding/base64"
2324
"encoding/json"
2425
"errors"
@@ -72,6 +73,7 @@ type defaultAuditor struct {
7273
password []byte
7374
auditDatabases []string
7475
auditSignature string
76+
publicKey *ecdsa.PublicKey
7577
notificationConfig AuditNotificationConfig
7678
serviceClient schema.ImmuServiceClient
7779
uuidProvider state.UUIDProvider
@@ -89,6 +91,7 @@ func DefaultAuditor(
8991
passwordBase64 string,
9092
auditDatabases []string,
9193
auditSignature string,
94+
publicKey *ecdsa.PublicKey,
9295
notificationConfig AuditNotificationConfig,
9396
serviceClient schema.ImmuServiceClient,
9497
uuidProvider state.UUIDProvider,
@@ -129,6 +132,7 @@ func DefaultAuditor(
129132
[]byte(password),
130133
auditDatabases,
131134
auditSignature,
135+
publicKey,
132136
notificationConfig,
133137
serviceClient,
134138
uuidProvider,
@@ -255,7 +259,7 @@ func (a *defaultAuditor) audit() error {
255259
}
256260

257261
if a.auditSignature == "validate" {
258-
if okSig, err := state.CheckSignature(); err != nil || !okSig {
262+
if okSig, err := state.CheckSignature(a.publicKey); err != nil || !okSig {
259263
a.logger.Errorf(
260264
"audit #%d aborted: could not verify signature on server state at %s @ %s",
261265
a.index, serverID, a.serverAddress)

0 commit comments

Comments
 (0)