Skip to content

Commit

Permalink
Add initial support for step ca init with cloud cas.
Browse files Browse the repository at this point in the history
  • Loading branch information
maraino committed Nov 3, 2020
1 parent 5a1e44a commit 2b4b902
Show file tree
Hide file tree
Showing 12 changed files with 717 additions and 114 deletions.
13 changes: 13 additions & 0 deletions cas/apiv1/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/x509"

"github.com/pkg/errors"
"github.com/smallstep/certificates/kms"
)

// Options represents the configuration options used to select and configure the
Expand All @@ -24,6 +25,18 @@ type Options struct {
// They are configured in ca.json crt and key properties.
Issuer *x509.Certificate `json:"-"`
Signer crypto.Signer `json:"-"`

// IsCreator is set to true when we're creating a certificate authority. Is
// used to skip some validations when initializing a CertificateAuthority.
IsCreator bool `json:"-"`

// KeyManager is the KMS used to generate keys in SoftCAS.
KeyManager kms.KeyManager `json:"-"`

// Project and Location are parameters used in CloudCAS to create a new
// certificate authority.
Project string `json:"-"`
Location string `json:"-"`
}

// Validate checks the fields in Options.
Expand Down
77 changes: 77 additions & 0 deletions cas/apiv1/requests.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,53 @@
package apiv1

import (
"crypto"
"crypto/x509"
"time"

"github.com/smallstep/certificates/kms/apiv1"
)

// CertificateAuthorityType indicates the type of Certificate Authority to
// create.
type CertificateAuthorityType int

const (
// RootCA is the type used to create a self-signed certificate suitable for
// use as a root CA.
RootCA CertificateAuthorityType = iota + 1

// IntermediateCA is the type used to create a subordinated certificate that
// can be used to sign additional leaf certificates.
IntermediateCA
)

// SignatureAlgorithm used for cryptographic signing.
type SignatureAlgorithm int

const (
// Not specified.
UnspecifiedSignAlgorithm SignatureAlgorithm = iota
// RSASSA-PKCS1-v1_5 key and a SHA256 digest.
SHA256WithRSA
// RSASSA-PKCS1-v1_5 key and a SHA384 digest.
SHA384WithRSA
// RSASSA-PKCS1-v1_5 key and a SHA512 digest.
SHA512WithRSA
// RSASSA-PSS key with a SHA256 digest.
SHA256WithRSAPSS
// RSASSA-PSS key with a SHA384 digest.
SHA384WithRSAPSS
// RSASSA-PSS key with a SHA512 digest.
SHA512WithRSAPSS
// ECDSA on the NIST P-256 curve with a SHA256 digest.
ECDSAWithSHA256
// ECDSA on the NIST P-384 curve with a SHA384 digest.
ECDSAWithSHA384
// ECDSA on the NIST P-521 curve with a SHA512 digest.
ECDSAWithSHA512
// EdDSA on Curve25519 with a SHA512 digest.
PureEd25519
)

// CreateCertificateRequest is the request used to sign a new certificate.
Expand Down Expand Up @@ -58,3 +103,35 @@ type GetCertificateAuthorityRequest struct {
type GetCertificateAuthorityResponse struct {
RootCertificate *x509.Certificate
}

// CreateCertificateAuthorityRequest ...
// This is a work in progress
type CreateCertificateAuthorityRequest struct {
Name string
Type CertificateAuthorityType
Template *x509.Certificate
Lifetime time.Duration
Backdate time.Duration
RequestID string
Project string
Location string

// Parent is the signer of the new CertificateAuthority.
Parent *CreateCertificateAuthorityResponse

// CreateKey defines the KMS CreateKeyRequest to use when creating a new
// CertificateAuthority. If CreateKey is nil, a default algorithm will be
// used.
CreateKey *apiv1.CreateKeyRequest
}

// CreateCertificateAuthorityResponse ...
// This is a work in progress
type CreateCertificateAuthorityResponse struct {
Name string
Certificate *x509.Certificate
CertificateChain []*x509.Certificate
PublicKey crypto.PublicKey
PrivateKey crypto.PrivateKey
Signer crypto.Signer
}
7 changes: 7 additions & 0 deletions cas/apiv1/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ type CertificateAuthorityGetter interface {
GetCertificateAuthority(req *GetCertificateAuthorityRequest) (*GetCertificateAuthorityResponse, error)
}

// CertificateAuthorityCreator is an interface implamented by a
// CertificateAuthorityService that has a method to create a new certificate
// authority.
type CertificateAuthorityCreator interface {
CreateCertificateAuthority(req *CreateCertificateAuthorityRequest) (*CreateCertificateAuthorityResponse, error)
}

// Type represents the CAS type used.
type Type string

Expand Down
36 changes: 32 additions & 4 deletions cas/cas.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import (

"github.com/pkg/errors"
"github.com/smallstep/certificates/cas/apiv1"

// Enable default implementation
_ "github.com/smallstep/certificates/cas/softcas"
"github.com/smallstep/certificates/cas/softcas"
)

// CertificateAuthorityService is the interface implemented by all the CAS.
type CertificateAuthorityService = apiv1.CertificateAuthorityService

// CertificateAuthorityCreator is the interface implemented by all CAS that can create a new authority.
type CertificateAuthorityCreator = apiv1.CertificateAuthorityCreator

// New creates a new CertificateAuthorityService using the given options.
func New(ctx context.Context, opts apiv1.Options) (CertificateAuthorityService, error) {
if err := opts.Validate(); err != nil {
return nil, err
Expand All @@ -26,7 +28,33 @@ func New(ctx context.Context, opts apiv1.Options) (CertificateAuthorityService,

fn, ok := apiv1.LoadCertificateAuthorityServiceNewFunc(t)
if !ok {
return nil, errors.Errorf("unsupported kms type '%s'", t)
return nil, errors.Errorf("unsupported cas type '%s'", t)
}
return fn(ctx, opts)
}

// NewCreator creates a new CertificateAuthorityCreator using the given options.
func NewCreator(ctx context.Context, opts apiv1.Options) (CertificateAuthorityCreator, error) {
t := apiv1.Type(strings.ToLower(opts.Type))
if t == apiv1.DefaultCAS {
t = apiv1.SoftCAS
}
if t == apiv1.SoftCAS {
return &softcas.SoftCAS{
KeyManager: opts.KeyManager,
}, nil
}

svc, err := New(ctx, opts)
if err != nil {
return nil, err
}

creator, ok := svc.(CertificateAuthorityCreator)
if !ok {

return nil, errors.Errorf("cas type '%s' does not implements CertificateAuthorityCreator", t)
}

return creator, nil
}
44 changes: 44 additions & 0 deletions cas/cloudcas/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import (
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"fmt"

"github.com/pkg/errors"
kmsapi "github.com/smallstep/certificates/kms/apiv1"
pb "google.golang.org/genproto/googleapis/cloud/security/privateca/v1beta1"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
Expand Down Expand Up @@ -326,3 +328,45 @@ func findExtraExtension(cert *x509.Certificate, oid asn1.ObjectIdentifier) (pkix
}
return pkix.Extension{}, false
}

func createKeyVersionSpec(alg kmsapi.SignatureAlgorithm, bits int) (*pb.CertificateAuthority_KeyVersionSpec, error) {
switch alg {
case kmsapi.UnspecifiedSignAlgorithm, kmsapi.ECDSAWithSHA256:
return &pb.CertificateAuthority_KeyVersionSpec{
KeyVersion: &pb.CertificateAuthority_KeyVersionSpec_Algorithm{
Algorithm: pb.CertificateAuthority_EC_P256_SHA256,
},
}, nil
case kmsapi.ECDSAWithSHA384:
return &pb.CertificateAuthority_KeyVersionSpec{
KeyVersion: &pb.CertificateAuthority_KeyVersionSpec_Algorithm{
Algorithm: pb.CertificateAuthority_EC_P384_SHA384,
},
}, nil
case kmsapi.SHA256WithRSAPSS:
algo, err := getRSAPSSAlgorithm(bits)
if err != nil {
return nil, err
}
return &pb.CertificateAuthority_KeyVersionSpec{
KeyVersion: &pb.CertificateAuthority_KeyVersionSpec_Algorithm{
Algorithm: algo,
},
}, nil
default:
return nil, fmt.Errorf("unknown or unsupported signature algorithm '%s'", bits)
}
}

func getRSAPSSAlgorithm(bits int) (pb.CertificateAuthority_SignHashAlgorithm, error) {
switch bits {
case 0, 3072:
return pb.CertificateAuthority_RSA_PSS_3072_SHA_256, nil
case 2048:
return pb.CertificateAuthority_RSA_PSS_2048_SHA_256, nil
case 4096:
return pb.CertificateAuthority_RSA_PSS_4096_SHA_256, nil
default:
return 0, fmt.Errorf("unsupported RSA-PSS key size '%d'", bits)
}
}
Loading

0 comments on commit 2b4b902

Please sign in to comment.