Skip to content

Commit c082ae1

Browse files
committed
Hashing sensitive info
Signed-off-by: Effi-S <effi.szt@gmail.com>
1 parent 5a3ac10 commit c082ae1

10 files changed

Lines changed: 137 additions & 9 deletions

File tree

token/services/identity/idemix/crypto/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func NewFabricCAIdemixConfig(issuerPublicKey []byte, dir string) (*Config, error
173173
func NewConfigFromRaw(issuerPublicKey []byte, configRaw []byte) (*Config, error) {
174174
config := &config.IdemixConfig{}
175175
if err := proto.Unmarshal(configRaw, config); err != nil {
176-
return nil, errors.Wrapf(err, "failed to unmarshal idemix config at [%s]", string(configRaw))
176+
return nil, errors.Wrapf(err, "failed to unmarshal idemix config of PK [%s]", utils.Hashable(issuerPublicKey))
177177
}
178178
// match public keys
179179
if !bytes.Equal(issuerPublicKey, config.Ipk) {

token/services/identity/idemix/crypto/deserializer.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
bccsp "github.com/IBM/idemix/bccsp/types"
1313
"github.com/LFDT-Panurus/panurus/token/services/identity/idemix/schema"
14+
"github.com/LFDT-Panurus/panurus/token/services/utils"
1415
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
1516
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/proto"
1617
)
@@ -112,7 +113,7 @@ func (d *Deserializer) DeserializeAgainstNymEID(identity []byte, nymEID []byte)
112113
func (d *Deserializer) DeserializeAuditInfo(_ context.Context, raw []byte) (*AuditInfo, error) {
113114
ai, err := DeserializeAuditInfo(raw)
114115
if err != nil {
115-
return nil, errors.Wrapf(err, "failed deserializing audit info [%s]", string(raw))
116+
return nil, errors.Wrapf(err, "failed deserializing audit info [%s]", utils.Hashable(raw))
116117
}
117118
ai.Csp = d.Csp
118119
ai.IssuerPublicKey = d.IssuerPublicKey

token/services/identity/idemix/deserializer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ type AuditInfoDeserializer struct{}
181181
func (c *AuditInfoDeserializer) DeserializeAuditInfo(ctx context.Context, identity driver.Identity, raw []byte) (driver2.AuditInfo, error) {
182182
ai, err := crypto2.DeserializeAuditInfo(raw)
183183
if err != nil {
184-
return nil, errors.Wrapf(err, "failed deserializing audit info [%s]", string(raw))
184+
return nil, errors.Wrapf(err, "failed deserializing audit info [%s]", utils.Hashable(raw))
185185
}
186186

187187
return ai, nil

token/services/identity/idemixnym/deserializer.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
driver2 "github.com/LFDT-Panurus/panurus/token/services/identity/driver"
1515
"github.com/LFDT-Panurus/panurus/token/services/identity/idemix"
1616
"github.com/LFDT-Panurus/panurus/token/services/identity/idemixnym/nym"
17+
"github.com/LFDT-Panurus/panurus/token/services/utils"
1718
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
1819
)
1920

@@ -103,7 +104,7 @@ type AuditInfoDeserializer struct{}
103104
func (c *AuditInfoDeserializer) DeserializeAuditInfo(ctx context.Context, identity driver.Identity, raw []byte) (driver2.AuditInfo, error) {
104105
ai, err := nym.DeserializeAuditInfo(raw)
105106
if err != nil {
106-
return nil, errors.Wrapf(err, "failed deserializing audit info [%s]", string(raw))
107+
return nil, errors.Wrapf(err, "failed deserializing audit info [%s]", utils.Hashable(raw))
107108
}
108109

109110
return ai, nil

token/services/identity/interop/htlc/deserializer.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/LFDT-Panurus/panurus/token/services/identity"
1515
idriver "github.com/LFDT-Panurus/panurus/token/services/identity/driver"
1616
"github.com/LFDT-Panurus/panurus/token/services/interop/htlc"
17+
"github.com/LFDT-Panurus/panurus/token/services/utils"
1718
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
1819
)
1920

@@ -182,14 +183,14 @@ func (a *AuditDeserializer) DeserializeAuditInfo(ctx context.Context, identity d
182183
si := &ScriptInfo{}
183184
err = json.Unmarshal(raw, si)
184185
if err != nil || (len(si.Sender) == 0 && len(si.Recipient) == 0) {
185-
return nil, errors.Errorf("invalid audit info, failed unmarshal [%s][%d][%d]", string(raw), len(si.Sender), len(si.Recipient))
186+
return nil, errors.Errorf("invalid audit info, failed unmarshal [%s][%d][%d]", utils.Hashable(raw), len(si.Sender), len(si.Recipient))
186187
}
187188
if len(si.Recipient) == 0 {
188189
return nil, errors.Errorf("no recipient defined")
189190
}
190191
ai, err := a.AuditInfoDeserializer.DeserializeAuditInfo(ctx, script.Recipient, si.Recipient)
191192
if err != nil {
192-
return nil, errors.Wrapf(err, "failed unmarshalling audit info [%s]", raw)
193+
return nil, errors.Wrapf(err, "failed unmarshalling audit info [%s]", utils.Hashable(raw))
193194
}
194195

195196
return ai, nil

token/services/identity/interop/htlc/validator.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
"github.com/LFDT-Panurus/panurus/token/services/identity"
1515
"github.com/LFDT-Panurus/panurus/token/services/interop/htlc"
16+
"github.com/LFDT-Panurus/panurus/token/services/utils"
1617
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
1718
)
1819

@@ -87,7 +88,7 @@ func MetadataClaimKeyCheck(action Action, script *htlc.Script, op OperationType,
8788
// Unmarshal signature to ClaimSignature
8889
claim := &htlc.ClaimSignature{}
8990
if err := json.Unmarshal(sig, claim); err != nil {
90-
return "", errors.Wrapf(err, "failed unmarshalling claim signature [%s]", string(sig))
91+
return "", errors.Wrapf(err, "failed unmarshalling claim signature [%s]", utils.Hashable(sig))
9192
}
9293
// Check that it is well-formed
9394
if len(claim.Preimage) == 0 || len(claim.RecipientSignature) == 0 {

token/services/identity/x509/crypto/config.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ SPDX-License-Identifier: Apache-2.0
77
package crypto
88

99
import (
10+
"fmt"
11+
1012
"github.com/LFDT-Panurus/panurus/token/services/identity/x509/crypto/pkcs11"
1113
"github.com/LFDT-Panurus/panurus/token/services/identity/x509/crypto/protos-go/v1/config"
1214
"github.com/go-viper/mapstructure/v2"
@@ -75,6 +77,20 @@ type KeyIDMapping struct {
7577
ID string `yaml:"ID,omitempty"`
7678
}
7779

80+
// String renders the PKCS11 configuration for logging with the PIN redacted, so
81+
// the secret can never reach a log line or error string, even when a *PKCS11 is
82+
// interpolated directly or as a field of a *BCCSP. It is nil-safe.
83+
func (p *PKCS11) String() string {
84+
if p == nil {
85+
return "<nil>"
86+
}
87+
88+
return fmt.Sprintf(
89+
"{Security:%d Hash:%s Library:%s Label:%s Pin:[REDACTED] SoftwareVerify:%t Immutable:%t AltID:%s KeyIDs:%v SessionCacheSize:%d}",
90+
p.Security, p.Hash, p.Library, p.Label, p.SoftwareVerify, p.Immutable, p.AltID, p.KeyIDs, p.SessionCacheSize,
91+
)
92+
}
93+
7894
// ToBCCSPOpts converts the passed opts to `config.BCCSP`
7995
func ToBCCSPOpts(boxed any) (*BCCSP, error) {
8096
opts := &Opts{}

token/services/identity/x509/crypto/msp.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"crypto/x509"
1313
"encoding/pem"
1414

15+
"github.com/LFDT-Panurus/panurus/token/services/utils"
1516
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
1617
"github.com/hyperledger/fabric-lib-go/bccsp"
1718
)
@@ -242,7 +243,7 @@ func (f *IdentityFactory) getCertFromPem(idBytes []byte) (*x509.Certificate, err
242243
// Decode the pem bytes
243244
pemCert, _ := pem.Decode(idBytes)
244245
if pemCert == nil {
245-
return nil, errors.Errorf("could not decode pem bytes [%v]", idBytes)
246+
return nil, errors.Errorf("could not decode pem bytes [%v]", utils.Hashable(idBytes))
246247
}
247248

248249
// get a cert

token/services/identity/x509/crypto/pkcs11/pkcs11.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ type (
3232
func NewProvider(opts PKCS11Opts, ks bccsp.KeyStore, mapper func(ski []byte) []byte) (*pkcs11.Provider, error) {
3333
csp, err := pkcs11.New(opts, ks, pkcs11.WithKeyMapper(mapper))
3434
if err != nil {
35-
return nil, errors.WithMessagef(err, "Failed initializing PKCS11 library with config [%+v]", opts)
35+
// redact the PIN on the copy so the secret never reaches the error string.
36+
safeOpts := opts
37+
safeOpts.Pin = "[REDACTED]"
38+
39+
return nil, errors.WithMessagef(err, "Failed initializing PKCS11 library with config [%+v]", safeOpts)
3640
}
3741
return csp, nil
3842
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package crypto
8+
9+
import (
10+
"fmt"
11+
"testing"
12+
13+
"github.com/hyperledger/fabric-lib-go/bccsp"
14+
"github.com/stretchr/testify/assert"
15+
"github.com/stretchr/testify/require"
16+
)
17+
18+
const testPIN = "s3cr3t-pin-9999"
19+
20+
// PKCS11.String must redact the PIN and never emit it verbatim, whether the
21+
// *PKCS11 is logged directly or as a field of a *BCCSP.
22+
func TestPKCS11_String_RedactsPin(t *testing.T) {
23+
p := &PKCS11{Library: "/usr/lib/libpkcs11.so", Label: "tok", Pin: testPIN}
24+
25+
s := p.String()
26+
assert.Contains(t, s, "[REDACTED]")
27+
assert.NotContains(t, s, testPIN)
28+
// Non-secret fields remain visible for debugging.
29+
assert.Contains(t, s, "/usr/lib/libpkcs11.so")
30+
assert.Contains(t, s, "tok")
31+
32+
// %v / %s go through the Stringer as well.
33+
assert.NotContains(t, fmt.Sprintf("%s", p), testPIN) //nolint:staticcheck // Explicitly checking fmt.Sprintf
34+
assert.NotContains(t, fmt.Sprintf("%+v", p), testPIN) //nolint:staticcheck // Explicitly checking fmt.Sprintf
35+
}
36+
37+
// A nil *PKCS11 must format without panicking (SW-only configs have a nil PKCS11).
38+
func TestPKCS11_String_Nil(t *testing.T) {
39+
var p *PKCS11
40+
assert.NotPanics(t, func() { _ = p.String() })
41+
assert.Equal(t, "<nil>", p.String())
42+
assert.NotPanics(t, func() { _ = fmt.Sprintf("%v", p) })
43+
}
44+
45+
// Formatting a *BCCSP (as setup.go and kmp.go do) must redact the nested PKCS11 PIN,
46+
// and must not panic when the PKCS11 field is nil.
47+
func TestBCCSP_Format_RedactsPin(t *testing.T) {
48+
t.Run("WithPKCS11", func(t *testing.T) {
49+
cfg := &BCCSP{Default: "PKCS11", PKCS11: &PKCS11{Label: "tok", Pin: testPIN}}
50+
out := fmt.Sprintf("%v", cfg)
51+
assert.Contains(t, out, "[REDACTED]")
52+
assert.NotContains(t, out, testPIN)
53+
})
54+
t.Run("NilPKCS11", func(t *testing.T) {
55+
cfg := &BCCSP{Default: "SW", SW: &SoftwareProvider{Hash: "SHA2", Security: 256}}
56+
assert.NotPanics(t, func() { _ = fmt.Sprintf("%v", cfg) })
57+
})
58+
t.Run("NilBCCSP", func(t *testing.T) {
59+
var cfg *BCCSP
60+
assert.NotPanics(t, func() { _ = fmt.Sprintf("%v", cfg) })
61+
})
62+
}
63+
64+
// getIdentityFactory must never mutate the caller's live config and must never panic,
65+
// across the nil, SW-only, and error paths. Regression test for the pointer-aliasing
66+
// redaction bug (Issue #2069) that overwrote the real PIN and dereferenced nil.
67+
func TestGetIdentityFactory_NoMutationNoPanic(t *testing.T) {
68+
conf := &Config{CryptoConfig: &CryptoConfig{SignatureHashFamily: bccsp.SHA2}}
69+
70+
t.Run("NilBccspConfig", func(t *testing.T) {
71+
// Default SW provider; nil bccspConfig is a supported, common path.
72+
assert.NotPanics(t, func() {
73+
_, err := getIdentityFactory(conf, nil, nil)
74+
require.NoError(t, err)
75+
})
76+
})
77+
78+
t.Run("SWOnlyConfigLeavesPinUntouched", func(t *testing.T) {
79+
bccspConfig := &BCCSP{
80+
Default: "SW",
81+
SW: &SoftwareProvider{Hash: "SHA2", Security: 256},
82+
// A PIN may be present even on the SW path; it must survive verbatim.
83+
PKCS11: &PKCS11{Label: "tok", Pin: testPIN},
84+
}
85+
86+
_, err := getIdentityFactory(conf, bccspConfig, nil)
87+
require.NoError(t, err)
88+
assert.Equal(t, testPIN, bccspConfig.PKCS11.Pin, "the caller's live PIN must not be mutated")
89+
})
90+
91+
t.Run("ErrorPathRedactsWithoutMutating", func(t *testing.T) {
92+
bccspConfig := &BCCSP{
93+
Default: "does-not-exist", // forces GetBCCSPFromConf to return an error
94+
PKCS11: &PKCS11{Label: "tok", Pin: testPIN},
95+
}
96+
97+
_, err := getIdentityFactory(conf, bccspConfig, nil)
98+
require.Error(t, err)
99+
assert.Contains(t, err.Error(), "[REDACTED]", "error must show redaction marker")
100+
assert.NotContains(t, err.Error(), testPIN, "error must not leak the PIN")
101+
assert.Equal(t, testPIN, bccspConfig.PKCS11.Pin, "the caller's live PIN must not be mutated")
102+
})
103+
}

0 commit comments

Comments
 (0)