agent/consul: key the public key of the CSR, verify in test

This commit is contained in:
Mitchell Hashimoto 2018-03-19 21:00:01 -07:00
parent 9a8653f45e
commit 1928c07d0c
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
4 changed files with 42 additions and 6 deletions

View File

@ -190,7 +190,8 @@ func TestLeaf(t testing.T, service string, root *structs.CARoot) string {
// TestCSR returns a CSR to sign the given service. // TestCSR returns a CSR to sign the given service.
func TestCSR(t testing.T, id SpiffeID) string { func TestCSR(t testing.T, id SpiffeID) string {
template := &x509.CertificateRequest{ template := &x509.CertificateRequest{
URIs: []*url.URL{id.URI()}, URIs: []*url.URL{id.URI()},
SignatureAlgorithm: x509.ECDSAWithSHA256,
} }
// Create the private key we'll use // Create the private key we'll use

View File

@ -71,7 +71,7 @@ func (s *ConnectCA) Roots(
// isn't right, we're not using enough of the CSR fields, etc. // isn't right, we're not using enough of the CSR fields, etc.
func (s *ConnectCA) Sign( func (s *ConnectCA) Sign(
args *structs.CASignRequest, args *structs.CASignRequest,
reply *structs.IndexedCARoots) error { reply *structs.IssuedCert) error {
// Parse the CSR // Parse the CSR
csr, err := connect.ParseCSR(args.CSR) csr, err := connect.ParseCSR(args.CSR)
if err != nil { if err != nil {
@ -132,14 +132,17 @@ func (s *ConnectCA) Sign(
SerialNumber: sn, SerialNumber: sn,
Subject: pkix.Name{CommonName: serviceId.Service}, Subject: pkix.Name{CommonName: serviceId.Service},
URIs: csr.URIs, URIs: csr.URIs,
SignatureAlgorithm: x509.ECDSAWithSHA256, Signature: csr.Signature,
SignatureAlgorithm: csr.SignatureAlgorithm,
PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
PublicKey: csr.PublicKey,
BasicConstraintsValid: true, BasicConstraintsValid: true,
KeyUsage: x509.KeyUsageDataEncipherment | x509.KeyUsageKeyAgreement, KeyUsage: x509.KeyUsageDataEncipherment | x509.KeyUsageKeyAgreement,
ExtKeyUsage: []x509.ExtKeyUsage{ ExtKeyUsage: []x509.ExtKeyUsage{
x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageClientAuth,
x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageServerAuth,
}, },
NotAfter: time.Now().Add(10 * 365 * 24 * time.Hour), NotAfter: time.Now().Add(3 * 24 * time.Hour),
NotBefore: time.Now(), NotBefore: time.Now(),
AuthorityKeyId: keyId, AuthorityKeyId: keyId,
SubjectKeyId: keyId, SubjectKeyId: keyId,
@ -157,5 +160,11 @@ func (s *ConnectCA) Sign(
return fmt.Errorf("error encoding private key: %s", err) return fmt.Errorf("error encoding private key: %s", err)
} }
// Set the response
*reply = structs.IssuedCert{
SerialNumber: template.SerialNumber,
Cert: buf.String(),
}
return nil return nil
} }

View File

@ -1,6 +1,7 @@
package consul package consul
import ( import (
"crypto/x509"
"os" "os"
"testing" "testing"
@ -30,13 +31,24 @@ func TestConnectCASign(t *testing.T) {
// Insert a CA // Insert a CA
state := s1.fsm.State() state := s1.fsm.State()
assert.Nil(state.CARootSet(1, connect.TestCA(t, nil))) ca := connect.TestCA(t, nil)
assert.Nil(state.CARootSet(1, ca))
// Generate a CSR and request signing // Generate a CSR and request signing
args := &structs.CASignRequest{ args := &structs.CASignRequest{
Datacenter: "dc01", Datacenter: "dc01",
CSR: connect.TestCSR(t, connect.TestSpiffeIDService(t, "web")), CSR: connect.TestCSR(t, connect.TestSpiffeIDService(t, "web")),
} }
var reply interface{} var reply structs.IssuedCert
assert.Nil(msgpackrpc.CallWithCodec(codec, "ConnectCA.Sign", args, &reply)) assert.Nil(msgpackrpc.CallWithCodec(codec, "ConnectCA.Sign", args, &reply))
// Verify that the cert is signed by the CA
roots := x509.NewCertPool()
assert.True(roots.AppendCertsFromPEM([]byte(ca.RootCert)))
leaf, err := connect.ParseCert(reply.Cert)
assert.Nil(err)
_, err = leaf.Verify(x509.VerifyOptions{
Roots: roots,
})
assert.Nil(err)
} }

View File

@ -1,5 +1,9 @@
package structs package structs
import (
"math/big"
)
// IndexedCARoots is the list of currently trusted CA Roots. // IndexedCARoots is the list of currently trusted CA Roots.
type IndexedCARoots struct { type IndexedCARoots struct {
// ActiveRootID is the ID of a root in Roots that is the active CA root. // ActiveRootID is the ID of a root in Roots that is the active CA root.
@ -62,3 +66,13 @@ type CASignRequest struct {
func (q *CASignRequest) RequestDatacenter() string { func (q *CASignRequest) RequestDatacenter() string {
return q.Datacenter return q.Datacenter
} }
// IssuedCert is a certificate that has been issued by a Connect CA.
type IssuedCert struct {
// SerialNumber is the unique serial number for this certificate.
SerialNumber *big.Int
// Cert is the PEM-encoded certificate. This should not be stored in the
// state store, but is present in the sign API response.
Cert string `json:",omitempty"`
}