Skip to content

Commit b3841e9

Browse files
committed
Add AES-GCM encryption support. Move argon2 to new crypto package. Default dev and debug config to ECC certs
1 parent acd102d commit b3841e9

File tree

10 files changed

+259
-51
lines changed

10 files changed

+259
-51
lines changed

configs/platform/config.debug.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,16 @@ certificate-authority:
203203
# Supported schemes: RSA_PSS | RSA_PKCS1v15
204204
rsa-scheme: RSA_PSS
205205

206-
# The default algorithm to use when creating keys and certificates
206+
# The key algorithm used for the CA signing certificate
207207
# Supported algorithms: RSA, ECC
208-
key-algorithm: RSA
208+
# key-algorithm: RSA
209+
key-algorithm: ECC
209210

210211
# The default signature algorithm
211212
# Any fully supported Go x509 SignatureAlgorithm:
212213
# https://pkg.go.dev/crypto/x509#SignatureAlgorithm
213-
signature-algorithm: SHA256WithRSA
214+
# signature-algorithm: SHA256WithRSA
215+
signature-algorithm: ECDSAWithSHA256
214216

215217
# The Elliptical Curve Cryptography Curve
216218
# Supported curves: P224, P256, P384, P521

configs/platform/config.dev.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,12 @@ certificate-authority:
197197

198198
# The default algorithm to use when creating keys and certificates
199199
# Supported algorithms: RSA, ECC
200-
key-algorithm: RSA
200+
key-algorithm: ECC
201201

202202
# The default signature algorithm
203203
# Any fully supported Go x509 SignatureAlgorithm:
204204
# https://pkg.go.dev/crypto/x509#SignatureAlgorithm
205-
signature-algorithm: SHA256WithRSA
205+
signature-algorithm: ECDSAWithSHA256
206206

207207
# The Elliptical Curve Cryptography Curve
208208
# Supported curves: P224, P256, P384, P521

configs/platform/config.fips.yaml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

44
# Global platform configs
5-
debug: true
5+
debug: false
66
debug-secrets: false
77
platform-dir: trusted-data
88
config-dir: trusted-data/etc
@@ -138,10 +138,10 @@ tpm:
138138
ek-cert: ../ECcert.bin
139139

140140
# Use TPM Simulator instead of real TPM
141-
simulator: true
141+
simulator: false
142142

143143
# Automatically import EK Platform (Manufacturer) Certificate(s) into trust store
144-
auto-import-ek-certs: true
144+
auto-import-ek-certs: false
145145

146146
# PCRs to use for local attestation
147147
# https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/
@@ -169,7 +169,7 @@ certificate-authority:
169169
issued-valid: 365
170170

171171
# Set to true to include "localhost" in SANS names
172-
sans-include-localhost: true
172+
sans-include-localhost: false
173173

174174
# Delete revoked certificates. They can be safely
175175
# discarded after revocation, but you may want them
@@ -217,7 +217,7 @@ certificate-authority:
217217

218218
# The Certificate Authority identity
219219
identity:
220-
- key-size: 2048
220+
- key-size: 4096
221221
# CA cert expiration (years)
222222
valid: 50
223223
subject:
@@ -309,4 +309,5 @@ argon2:
309309
iterations: 2
310310
parallelism: 1
311311
saltLen: 16
312-
keyLen: 32
312+
keyLen: 32
313+

pkg/app/app.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717

1818
"github.com/jeremyhahn/go-trusted-platform/pkg/ca"
1919
"github.com/jeremyhahn/go-trusted-platform/pkg/config"
20-
"github.com/jeremyhahn/go-trusted-platform/pkg/hash"
20+
"github.com/jeremyhahn/go-trusted-platform/pkg/crypto/argon2"
2121
"github.com/jeremyhahn/go-trusted-platform/pkg/pkcs11"
2222
"github.com/jeremyhahn/go-trusted-platform/pkg/platform/auth"
2323
"github.com/jeremyhahn/go-trusted-platform/pkg/platform/setup"
@@ -35,25 +35,25 @@ type App struct {
3535
CA ca.CertificateAuthority `yaml:"-" json:"-" mapstructure:"-"`
3636
TPM tpm2.TrustedPlatformModule2 `yaml:"-" json:"-" mapstructure:"-"`
3737
PKCS11 pkcs11.PKCS11
38-
CAConfig ca.Config `yaml:"certificate-authority" json:"certificate_authority" mapstructure:"certificate-authority"`
39-
TPMConfig tpm2.Config `yaml:"tpm" json:"tpm" mapstructure:"tpm"`
40-
PKCS11Config pkcs11.Config `yaml:"pkcs11" json:"pkcs11" mapstructure:"pkcs11"`
41-
AttestationConfig config.Attestation `yaml:"attestation" json:"attestation" mapstructure:"attestation"`
42-
DebugFlag bool `yaml:"debug" json:"debug" mapstructure:"debug"`
43-
DebugSecretsFlag bool `yaml:"debug-secrets" json:"debug-secrets" mapstructure:"debug-secrets"`
44-
PlatformDir string `yaml:"platform-dir" json:"platform_dir" mapstructure:"platform-dir"`
45-
ConfigDir string `yaml:"config-dir" json:"config_dir" mapstructure:"config-dir"`
46-
LogDir string `yaml:"log-dir" json:"log_dir" mapstructure:"log-dir"`
47-
Logger *logging.Logger `yaml:"-" json:"-" mapstructure:"-"`
48-
RuntimeUser string `yaml:"runtime-user" json:"runtime_user" mapstructure:"runtime-user"`
49-
Argon2 hash.Argon2Params `yaml:"argon2" json:"argon2" mapstructure:"argon2"`
50-
WebService config.WebService `yaml:"webservice" json:"webservice" mapstructure:"webservice"`
51-
PasswordPolicy string `yaml:"password-policy" json:"password-policy" mapstructure:"password-policy"`
52-
RootPassword string `yaml:"root-password" json:"root_password" mapstructure:"root-password"`
53-
IntermediatePassword string `yaml:"intermediate-password" json:"intermediate_password" mapstructure:"intermediate-password"`
54-
ServerPassword string `yaml:"server-password" json:"server_password" mapstructure:"server-password"`
55-
EKAuth string `yaml:"ek-auth" json:"ek_auth mapstructure:"ek-auth"`
56-
SRKAuth string `yaml:"srk-auth" json:"srk_auth mapstructure:"srk-auth"`
38+
CAConfig ca.Config `yaml:"certificate-authority" json:"certificate_authority" mapstructure:"certificate-authority"`
39+
TPMConfig tpm2.Config `yaml:"tpm" json:"tpm" mapstructure:"tpm"`
40+
PKCS11Config pkcs11.Config `yaml:"pkcs11" json:"pkcs11" mapstructure:"pkcs11"`
41+
AttestationConfig config.Attestation `yaml:"attestation" json:"attestation" mapstructure:"attestation"`
42+
DebugFlag bool `yaml:"debug" json:"debug" mapstructure:"debug"`
43+
DebugSecretsFlag bool `yaml:"debug-secrets" json:"debug-secrets" mapstructure:"debug-secrets"`
44+
PlatformDir string `yaml:"platform-dir" json:"platform_dir" mapstructure:"platform-dir"`
45+
ConfigDir string `yaml:"config-dir" json:"config_dir" mapstructure:"config-dir"`
46+
LogDir string `yaml:"log-dir" json:"log_dir" mapstructure:"log-dir"`
47+
Logger *logging.Logger `yaml:"-" json:"-" mapstructure:"-"`
48+
RuntimeUser string `yaml:"runtime-user" json:"runtime_user" mapstructure:"runtime-user"`
49+
Argon2 argon2.Argon2Params `yaml:"argon2" json:"argon2" mapstructure:"argon2"`
50+
WebService config.WebService `yaml:"webservice" json:"webservice" mapstructure:"webservice"`
51+
PasswordPolicy string `yaml:"password-policy" json:"password-policy" mapstructure:"password-policy"`
52+
RootPassword string `yaml:"root-password" json:"root_password" mapstructure:"root-password"`
53+
IntermediatePassword string `yaml:"intermediate-password" json:"intermediate_password" mapstructure:"intermediate-password"`
54+
ServerPassword string `yaml:"server-password" json:"server_password" mapstructure:"server-password"`
55+
EKAuth string `yaml:"ek-auth" json:"ek_auth mapstructure:"ek-auth"`
56+
SRKAuth string `yaml:"srk-auth" json:"srk_auth mapstructure:"srk-auth"`
5757
cAPassword string
5858
}
5959

pkg/config.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,16 @@ certificate-authority:
203203
# Supported schemes: RSA_PSS | RSA_PKCS1v15
204204
rsa-scheme: RSA_PSS
205205

206-
# The default algorithm to use when creating keys and certificates
206+
# The key algorithm used for the CA signing certificate
207207
# Supported algorithms: RSA, ECC
208-
key-algorithm: RSA
208+
# key-algorithm: RSA
209+
key-algorithm: ECC
209210

210211
# The default signature algorithm
211212
# Any fully supported Go x509 SignatureAlgorithm:
212213
# https://pkg.go.dev/crypto/x509#SignatureAlgorithm
213-
signature-algorithm: SHA256WithRSA
214+
# signature-algorithm: SHA256WithRSA
215+
signature-algorithm: ECDSAWithSHA256
214216

215217
# The Elliptical Curve Cryptography Curve
216218
# Supported curves: P224, P256, P384, P521

pkg/crypto/aesgcm/aesgcm.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package aesgcm
2+
3+
import (
4+
"crypto/aes"
5+
"crypto/cipher"
6+
"crypto/rand"
7+
"errors"
8+
"fmt"
9+
"io"
10+
11+
"github.com/op/go-logging"
12+
)
13+
14+
var (
15+
ErrInvalidNonce = errors.New("crypto/cipher: incorrect nonce length given to GCM")
16+
ErrMessageTooLarge = errors.New("crypto/cipher: message too large for GCM")
17+
ErrInvalidBufferOverlap = errors.New("crypto/cipher: invalid buffer overlap")
18+
)
19+
20+
type AESGCM struct {
21+
logger *logging.Logger
22+
debugSecrets bool
23+
random io.Reader
24+
}
25+
26+
// AES CGM encrypter / decrypter. Accepts a logger and optional source of
27+
// entropy, such as the TPM or an HSM. A randomly generated nonce, not exceeding
28+
// 96 bits, is automatically generated to add nonce misuse-resistance.
29+
//
30+
// In addition, this code wraps the panic that the Golang runtime throws
31+
// when a nonce is incorrect, a message is too large, or a buffer overlap is
32+
// detected, and returns a recoverable error instead of allowing it to crash
33+
// servers.
34+
// https://pkg.go.dev/crypto/cipher
35+
// https://datatracker.ietf.org/doc/html/rfc8452
36+
func NewAESGCM(
37+
logger *logging.Logger,
38+
debugSecrets bool,
39+
random io.Reader) AESGCM {
40+
41+
if random == nil {
42+
random = rand.Reader
43+
}
44+
return AESGCM{
45+
logger: logger,
46+
debugSecrets: debugSecrets,
47+
random: random,
48+
}
49+
}
50+
51+
// Seal the provided plain-test and "additional data" data
52+
// with the specified encryption key, using AES256 in GCM mode,
53+
// which provides authenticated encryption. Returns the ciphertext
54+
// and a nonce, used as the Initialization Vector for the AES
55+
// counter mode.
56+
func (this AESGCM) Seal(key, data, additionalData []byte) ([]byte, []byte, error) {
57+
58+
block, err := aes.NewCipher(key)
59+
if err != nil {
60+
return nil, nil, err
61+
}
62+
63+
// IV's longer than 96 bits require additional calcuations
64+
// https://crypto.stackexchange.com/questions/41601/aes-gcm-recommended-iv-size-why-12-bytes
65+
nonce := make([]byte, 12)
66+
if _, err := io.ReadFull(this.random, nonce); err != nil {
67+
return nil, nil, err
68+
}
69+
70+
aesgcm, err := cipher.NewGCM(block)
71+
if err != nil {
72+
return nil, nil, err
73+
}
74+
75+
ciphertext := aesgcm.Seal(nil, nonce, data, additionalData)
76+
77+
if this.debugSecrets {
78+
this.logger.Debugf("aesgcm/Seal: key: %s", string(key))
79+
this.logger.Debugf("aesgcm/Seal: data: %s", string(data))
80+
this.logger.Debugf("aesgcm/Seal: additionalData: %s", string(data))
81+
}
82+
83+
this.logger.Debugf("aesgcm/Seal: ciphtertext: %x\n", ciphertext)
84+
this.logger.Debugf("aesgcm/Seal: nonce: %x\n", nonce)
85+
86+
return ciphertext, nonce, nil
87+
}
88+
89+
// Seal encrypts and authenticates plaintext, authenticates the
90+
// additional data and
91+
func (this AESGCM) Open(key, ciphertext, nonce, additionalData []byte) (plaintext []byte, err error) {
92+
block, err := aes.NewCipher(key)
93+
if err != nil {
94+
this.logger.Error(err)
95+
return nil, err
96+
}
97+
aesgcm, err := cipher.NewGCM(block)
98+
if err != nil {
99+
this.logger.Error(err)
100+
return nil, err
101+
}
102+
defer func() error {
103+
// Recover from panic to keep prevent servers from crashing
104+
if r := recover(); r != nil {
105+
this.logger.Debugf("aesgcm/Open: panic: %s", r)
106+
err = fmt.Errorf("%s", r)
107+
}
108+
return nil
109+
}()
110+
plaintext, err = aesgcm.Open(nil, nonce, ciphertext, additionalData)
111+
if err != nil {
112+
this.logger.Error(err)
113+
return nil, err
114+
}
115+
116+
return plaintext, nil
117+
}

pkg/crypto/aesgcm/aesgcm_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package aesgcm
2+
3+
import (
4+
"crypto/rand"
5+
"io"
6+
"os"
7+
"testing"
8+
9+
"github.com/op/go-logging"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestSealWithoutAdditionalData(t *testing.T) {
14+
15+
logger := createLogger()
16+
17+
// Use rand.Reader for entropy
18+
aesgcm := NewAESGCM(logger, true, nil)
19+
20+
// Generate a key
21+
key := make([]byte, 32)
22+
_, err := io.ReadFull(rand.Reader, key)
23+
assert.Nil(t, err)
24+
25+
// Seal the data and get back the cipher-text and nonce
26+
secret := []byte("my-secret")
27+
ciphertext, nonce, err := aesgcm.Seal(key, secret, nil)
28+
29+
// Open the cipher-text using the nonce returned from Seal
30+
decrypted, err := aesgcm.Open(key, ciphertext, nonce, nil)
31+
assert.Nil(t, err)
32+
assert.Equal(t, secret, decrypted)
33+
34+
// Ensure failure with a bad nonce
35+
_, err = aesgcm.Open(key, ciphertext, []byte("foo"), nil)
36+
assert.NotNil(t, err)
37+
assert.Equal(t, ErrInvalidNonce, err)
38+
}
39+
40+
func TestSealWithAdditionalData(t *testing.T) {
41+
42+
logger := createLogger()
43+
44+
// Use rand.Reader for entropy
45+
aesgcm := NewAESGCM(logger, true, nil)
46+
47+
// Generate a key
48+
key := make([]byte, 32)
49+
_, err := io.ReadFull(rand.Reader, key)
50+
assert.Nil(t, err)
51+
52+
// Create "additional data". The Open operation will fail
53+
// if the additional data does not match the same data
54+
// that was passed to Seal.
55+
additionalData := []byte("some authorization data")
56+
57+
// Seal the data and get back the cipher-text and nonce
58+
secret := []byte("my-secret")
59+
ciphertext, nonce, err := aesgcm.Seal(key, secret, additionalData)
60+
61+
// Open the cipher-text using the nonce returned from Seal
62+
decrypted, err := aesgcm.Open(key, ciphertext, nonce, additionalData)
63+
assert.Nil(t, err)
64+
assert.Equal(t, secret, decrypted)
65+
66+
// Ensure failure when additional data doesnt match
67+
_, err = aesgcm.Open(key, ciphertext, nonce, []byte("foo"))
68+
assert.NotNil(t, err)
69+
}
70+
71+
// Create a logger for the tests
72+
func createLogger() *logging.Logger {
73+
stdout := logging.NewLogBackend(os.Stdout, "", 0)
74+
logging.SetBackend(stdout)
75+
logger := logging.MustGetLogger("tpm")
76+
77+
logFormat := logging.MustStringFormatter(
78+
`%{color}%{time:15:04:05.000} %{shortpkg}.%{shortfunc} %{level:.4s} %{id:03x}%{color:reset} %{message}`,
79+
)
80+
logFormatter := logging.NewBackendFormatter(stdout, logFormat)
81+
backends := logging.MultiLogger(stdout, logFormatter)
82+
logging.SetBackend(backends)
83+
84+
return logger
85+
}

pkg/hash/argon2.go renamed to pkg/crypto/argon2/argon2id.go

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package hash
1+
package argon2
22

33
import (
44
"crypto/subtle"
@@ -12,23 +12,10 @@ import (
1212
)
1313

1414
var (
15-
ErrInvalidHash = errors.New("argon2di: invalid format")
16-
ErrIncompatibleVersion = errors.New("argon2di: version incompatible")
15+
ErrInvalidHash = errors.New("argon2id: invalid format")
16+
ErrIncompatibleVersion = errors.New("argon2id: version incompatible")
1717
)
1818

19-
type Argon2Params struct {
20-
Memory uint32 `yaml:"memory" json:"memory" mapstructure:"memory"`
21-
Iterations uint32 `yaml:"iterations" json:"iterations" mapstructure:"iterations"`
22-
Parallelism uint8 `yaml:"parallelism" json:"parallelism" mapstructure:"parallelism"`
23-
SaltLength uint32 `yaml:"saltLen" json:"saltLen" mapstructure:"saltLen"`
24-
KeyLength uint32 `yaml:"keyLen" json:"keyLen" mapstructure:"keyLen"`
25-
}
26-
27-
type Argon2 interface {
28-
Hash(password string) (string, error)
29-
Compare(password, hash string) (match bool, err error)
30-
}
31-
3219
type Argon2Hasher struct {
3320
random io.Reader
3421
params Argon2Params

pkg/hash/argon2_test.go renamed to pkg/crypto/argon2/argon2id_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package hash
1+
package argon2
22

33
import (
44
"crypto/rand"

0 commit comments

Comments
 (0)