2022-10-11 15:18:19 +00:00
package pki
import (
"bytes"
2022-10-13 23:06:43 +00:00
"crypto/x509"
2022-10-13 22:09:32 +00:00
"encoding/json"
2022-10-11 15:18:19 +00:00
"os"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
2022-10-13 22:09:32 +00:00
"go.step.sm/crypto/jose"
"go.step.sm/linkedca"
2022-10-11 15:18:19 +00:00
"github.com/smallstep/certificates/cas/apiv1"
)
func TestPKI_WriteHelmTemplate ( t * testing . T ) {
type fields struct {
casOptions apiv1 . Options
pkiOptions [ ] Option
}
tests := [ ] struct {
name string
fields fields
testFile string
wantErr bool
} {
{
name : "ok/simple" ,
fields : fields {
pkiOptions : [ ] Option {
WithHelm ( ) ,
} ,
casOptions : apiv1 . Options {
Type : "softcas" ,
IsCreator : true ,
} ,
} ,
testFile : "testdata/helm/simple.yml" ,
wantErr : false ,
} ,
2022-10-13 22:09:32 +00:00
{
name : "ok/with-provisioner" ,
fields : fields {
pkiOptions : [ ] Option {
WithHelm ( ) ,
WithProvisioner ( "a-provisioner" ) ,
} ,
casOptions : apiv1 . Options {
Type : "softcas" ,
IsCreator : true ,
} ,
} ,
testFile : "testdata/helm/with-provisioner.yml" ,
wantErr : false ,
} ,
2022-10-11 15:18:19 +00:00
{
name : "ok/with-acme" ,
fields : fields {
pkiOptions : [ ] Option {
WithHelm ( ) ,
WithACME ( ) ,
} ,
casOptions : apiv1 . Options {
Type : "softcas" ,
IsCreator : true ,
} ,
} ,
testFile : "testdata/helm/with-acme.yml" ,
wantErr : false ,
} ,
{
name : "ok/with-admin" ,
fields : fields {
pkiOptions : [ ] Option {
WithHelm ( ) ,
WithAdmin ( ) ,
} ,
casOptions : apiv1 . Options {
Type : "softcas" ,
IsCreator : true ,
} ,
} ,
testFile : "testdata/helm/with-admin.yml" ,
wantErr : false ,
} ,
{
name : "ok/with-ssh" ,
fields : fields {
pkiOptions : [ ] Option {
WithHelm ( ) ,
WithSSH ( ) ,
} ,
casOptions : apiv1 . Options {
Type : "softcas" ,
IsCreator : true ,
} ,
} ,
testFile : "testdata/helm/with-ssh.yml" ,
wantErr : false ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
o := tt . fields . casOptions
opts := tt . fields . pkiOptions
2022-10-11 15:39:35 +00:00
// TODO(hs): invoking `New` doesn't perform all operations that are executed
// when `ca init --helm` is executed. The list of provisioners on the authority
// is not populated, for example, resulting in this test not being entirely
// realistic. Ideally this logic should be handled in one place and probably
// inside of the PKI initialization, but if that becomes messy, some more
// logic needs to be performed here to get the PKI instance in good shape.
2022-10-11 15:18:19 +00:00
p , err := New ( o , opts ... )
assert . NoError ( t , err )
2022-10-13 22:09:32 +00:00
2022-10-13 23:06:43 +00:00
// setKeyPair sets a predefined JWK and a default JWK provisioner. This is one
2022-10-13 22:09:32 +00:00
// of the things performed in the `ca init` code that's not part of `New`, but
// performed after that in p.GenerateKeyPairs`. We're currently using the same
// JWK for every test to keep test variance small: we're not testing JWK generation
// here after all. It's a bit dangerous to redefine the function here, but it's
// the simplest way to make this fully testable without refactoring the init now.
2022-10-13 23:06:43 +00:00
// The password for the predefined encrypted key is \x01\x03\x03\x07.
setKeyPair ( t , p )
// setFiles sets some static intermediate and root CA certificate bytes. It
// replaces the logic executed in `p.GenerateRootCertificate`, `p.WriteRootCertificate`,
// and `p.GenerateIntermediateCertificate`.
setFiles ( t , p )
2022-10-13 22:09:32 +00:00
2022-10-11 15:18:19 +00:00
w := & bytes . Buffer { }
if err := p . WriteHelmTemplate ( w ) ; ( err != nil ) != tt . wantErr {
t . Errorf ( "PKI.WriteHelmTemplate() error = %v, wantErr %v" , err , tt . wantErr )
return
}
2022-10-13 22:09:32 +00:00
2022-10-11 15:18:19 +00:00
wantBytes , err := os . ReadFile ( tt . testFile )
assert . NoError ( t , err )
if diff := cmp . Diff ( wantBytes , w . Bytes ( ) ) ; diff != "" {
t . Logf ( "Generated Helm template did not match reference %q\n" , tt . testFile )
t . Errorf ( "Diff follows:\n%s\n" , diff )
2022-10-13 23:06:43 +00:00
t . Errorf ( "Full output:\n%s\n" , w . Bytes ( ) )
2022-10-11 15:18:19 +00:00
}
} )
}
}
2022-10-13 22:09:32 +00:00
2022-10-13 23:06:43 +00:00
// setKeyPair sets a predefined JWK and a default JWK provisioner.
func setKeyPair ( t * testing . T , p * PKI ) {
2022-10-13 22:09:32 +00:00
t . Helper ( )
var err error
p . ottPublicKey , err = jose . ParseKey ( [ ] byte ( ` { "use":"sig","kty":"EC","kid":"zsUmysmDVoGJ71YoPHyZ-68tNihDaDaO5Mu7xX3M-_I","crv":"P-256","alg":"ES256","x":"Pqnua4CzqKz6ua41J3yeWZ1sRkGt0UlCkbHv8H2DGuY","y":"UhoZ_2ItDen9KQTcjay-ph-SBXH0mwqhHyvrrqIFDOI"} ` ) )
if err != nil {
t . Fatal ( err )
}
p . ottPrivateKey , err = jose . ParseEncrypted ( "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiZjVvdGVRS2hvOXl4MmQtSGlMZi05QSJ9.eYA6tt3fNuUpoxKWDT7P0Lbn2juxhEbTxEnwEMbjlYLLQ3sxL-dYTA.ven-FhmdjlC9itH0.a2jRTarN9vPd6F_mWnNBlOn6KbfMjCApmci2t65XbAsLzYFzhI_79Ykm5ueMYTupWLTjBJctl-g51ZHmsSB55pStbpoyyLNAsUX2E1fTmHe-Ni8bRrspwLv15FoN1Xo1g0mpR-ufWIFxOsW-QIfnMmMIIkygVuHFXmg2tFpzTNNG5aS29K3dN2nyk0WJrdIq79hZSTqVkkBU25Yu3A46sgjcM86XcIJJ2XUEih_KWEa6T1YrkixGu96pebjVqbO0R6dbDckfPF7FqNnwPHVtb1ACFpEYoOJVIbUCMaARBpWsxYhjJZlEM__XA46l8snFQDkNY3CdN0p1_gF3ckA.JLmq9nmu1h9oUi1S8ZxYjA" )
if err != nil {
t . Fatal ( err )
}
var claims * linkedca . Claims
if p . options . enableSSH {
claims = & linkedca . Claims {
Ssh : & linkedca . SSHClaims {
Enabled : true ,
} ,
}
}
// Add JWK provisioner to the configuration.
publicKey , err := json . Marshal ( p . ottPublicKey )
if err != nil {
t . Fatal ( err )
}
encryptedKey , err := p . ottPrivateKey . CompactSerialize ( )
if err != nil {
t . Fatal ( err )
}
p . Authority . Provisioners = append ( p . Authority . Provisioners , & linkedca . Provisioner {
Type : linkedca . Provisioner_JWK ,
Name : p . options . provisioner ,
Claims : claims ,
Details : & linkedca . ProvisionerDetails {
Data : & linkedca . ProvisionerDetails_JWK {
JWK : & linkedca . JWKProvisioner {
PublicKey : publicKey ,
EncryptedPrivateKey : [ ] byte ( encryptedKey ) ,
} ,
} ,
} ,
} )
}
2022-10-13 23:06:43 +00:00
// setFiles sets some static, gibberish intermediate and root CA certificate bytes.
func setFiles ( t * testing . T , p * PKI ) {
p . Files [ "/home/step/certs/root_ca.crt" ] = encodeCertificate ( & x509 . Certificate { Raw : [ ] byte ( "these are just some fake root CA cert bytes" ) } )
p . Files [ "/home/step/certs/intermediate_ca.crt" ] = encodeCertificate ( & x509 . Certificate { Raw : [ ] byte ( "these are just some fake intermediate CA cert bytes" ) } )
}