diff --git a/cmd/nebula-cert/ca.go b/cmd/nebula-cert/ca.go index 3145f445..d73c7c42 100644 --- a/cmd/nebula-cert/ca.go +++ b/cmd/nebula-cert/ca.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "math" + "math/bits" "net/netip" "os" "strings" @@ -44,6 +45,20 @@ type caFlags struct { } func newCaFlags() *caFlags { + // prevent running out of memory on 32-bit systems by defaulting to + // RFC9106's recommendation for memory-constrained environments + var ( + defaultArgonMemory uint + defaultArgonIterations uint + ) + if bits.UintSize == 32 { + defaultArgonMemory = 64 * 1024 + defaultArgonIterations = 3 + } else { + defaultArgonMemory = 2 * 1024 * 1024 + defaultArgonIterations = 1 + } + cf := caFlags{set: flag.NewFlagSet("ca", flag.ContinueOnError)} cf.set.Usage = func() {} cf.name = cf.set.String("name", "", "Required: name of the certificate authority") @@ -55,9 +70,9 @@ func newCaFlags() *caFlags { cf.groups = cf.set.String("groups", "", "Optional: comma separated list of groups. This will limit which groups subordinate certs can use") cf.networks = cf.set.String("networks", "", "Optional: comma separated list of ip address and network in CIDR notation. This will limit which ip addresses and networks subordinate certs can use in networks") cf.unsafeNetworks = cf.set.String("unsafe-networks", "", "Optional: comma separated list of ip address and network in CIDR notation. This will limit which ip addresses and networks subordinate certs can use in unsafe networks") - cf.argonMemory = cf.set.Uint("argon-memory", 2*1024*1024, "Optional: Argon2 memory parameter (in KiB) used for encrypted private key passphrase") + cf.argonMemory = cf.set.Uint("argon-memory", defaultArgonMemory, "Optional: Argon2 memory parameter (in KiB) used for encrypted private key passphrase") cf.argonParallelism = cf.set.Uint("argon-parallelism", 4, "Optional: Argon2 parallelism parameter used for encrypted private key passphrase") - cf.argonIterations = cf.set.Uint("argon-iterations", 1, "Optional: Argon2 iterations parameter used for encrypted private key passphrase") + cf.argonIterations = cf.set.Uint("argon-iterations", defaultArgonIterations, "Optional: Argon2 iterations parameter used for encrypted private key passphrase") cf.encryption = cf.set.Bool("encrypt", false, "Optional: prompt for passphrase and write out-key in an encrypted format") cf.curve = cf.set.String("curve", "25519", "EdDSA/ECDSA Curve (25519, P256)") cf.p11url = p11Flag(cf.set) diff --git a/cmd/nebula-cert/ca_test.go b/cmd/nebula-cert/ca_test.go index ce0113b6..e2389ceb 100644 --- a/cmd/nebula-cert/ca_test.go +++ b/cmd/nebula-cert/ca_test.go @@ -7,7 +7,9 @@ import ( "bytes" "encoding/pem" "errors" + "math/bits" "os" + "strconv" "strings" "testing" "time" @@ -22,6 +24,18 @@ func Test_caSummary(t *testing.T) { } func Test_caHelp(t *testing.T) { + var ( + defaultArgonMemory string + defaultArgonIterations string + ) + if bits.UintSize == 32 { + defaultArgonMemory = strconv.Itoa(64 * 1024) + defaultArgonIterations = strconv.Itoa(3) + } else { + defaultArgonMemory = strconv.Itoa(2 * 1024 * 1024) + defaultArgonIterations = strconv.Itoa(1) + } + ob := &bytes.Buffer{} caHelp(ob) assert.Equal( @@ -29,9 +43,9 @@ func Test_caHelp(t *testing.T) { "Usage of "+os.Args[0]+" ca : create a self signed certificate authority\n"+ " Pass \"-\" to any path flag to read from stdin or write to stdout.\n"+ " -argon-iterations uint\n"+ - " \tOptional: Argon2 iterations parameter used for encrypted private key passphrase (default 1)\n"+ + " \tOptional: Argon2 iterations parameter used for encrypted private key passphrase (default "+defaultArgonIterations+")\n"+ " -argon-memory uint\n"+ - " \tOptional: Argon2 memory parameter (in KiB) used for encrypted private key passphrase (default 2097152)\n"+ + " \tOptional: Argon2 memory parameter (in KiB) used for encrypted private key passphrase (default "+defaultArgonMemory+")\n"+ " -argon-parallelism uint\n"+ " \tOptional: Argon2 parallelism parameter used for encrypted private key passphrase (default 4)\n"+ " -curve string\n"+ @@ -188,10 +202,16 @@ func Test_ca(t *testing.T) { k, _ := pem.Decode(rb) ned, err := cert.UnmarshalNebulaEncryptedData(k.Bytes) require.NoError(t, err) - // we won't know salt in advance, so just check start of string - assert.Equal(t, uint32(2*1024*1024), ned.EncryptionMetadata.Argon2Parameters.Memory) + + if bits.UintSize == 32 { + assert.Equal(t, uint32(64*1024), ned.EncryptionMetadata.Argon2Parameters.Memory) + assert.Equal(t, uint32(3), ned.EncryptionMetadata.Argon2Parameters.Iterations) + } else { + assert.Equal(t, uint32(2*1024*1024), ned.EncryptionMetadata.Argon2Parameters.Memory) + assert.Equal(t, uint32(1), ned.EncryptionMetadata.Argon2Parameters.Iterations) + } + assert.Equal(t, uint8(4), ned.EncryptionMetadata.Argon2Parameters.Parallelism) - assert.Equal(t, uint32(1), ned.EncryptionMetadata.Argon2Parameters.Iterations) // verify the key is valid and decrypt-able var curve cert.Curve