diff --git a/fsthttp/backend.go b/fsthttp/backend.go index f01aab2..187b296 100644 --- a/fsthttp/backend.go +++ b/fsthttp/backend.go @@ -7,6 +7,7 @@ import ( "time" "github.com/fastly/compute-sdk-go/internal/abi/fastly" + "github.com/fastly/compute-sdk-go/secretstore" ) var ( @@ -244,41 +245,67 @@ func (b *BackendOptions) UseSSL(v bool) *BackendOptions { } // SSLMinVersion sets the minimum allowed TLS version on SSL connections to this backend. +// Setting this will enable SSL for the connection as a side effect. func (b *BackendOptions) SSLMinVersion(min TLSVersion) *BackendOptions { + b.abiOpts.UseSSL(true) b.abiOpts.SSLMinVersion(fastly.TLSVersion(min)) return b } // SSLMaxVersion sets the maximum allowed TLS version on SSL connections to this backend. +// Setting this will enable SSL for the connection as a side effect. func (b *BackendOptions) SSLMaxVersion(max TLSVersion) *BackendOptions { + b.abiOpts.UseSSL(true) b.abiOpts.SSLMaxVersion(fastly.TLSVersion(max)) return b } // CertHostname sets the hostname that the server certificate should declare. +// Setting this will enable SSL for the connection as a side effect. func (b *BackendOptions) CertHostname(host string) *BackendOptions { + b.abiOpts.UseSSL(true) b.abiOpts.CertHostname(host) return b } // CACert sets the CA certificate to use when checking the validity of the backend. +// Setting this will enable SSL for the connection as a side effect. func (b *BackendOptions) CACert(cert string) *BackendOptions { + b.abiOpts.UseSSL(true) b.abiOpts.CACert(cert) return b } // Ciphers sets the list of OpenSSL ciphers to support for connections to this origin. +// Setting this will enable SSL for the connection as a side effect. func (b *BackendOptions) Ciphers(ciphers string) *BackendOptions { + b.abiOpts.UseSSL(true) b.abiOpts.Ciphers(ciphers) return b } // SNIHostname sets the SNI hostname to use on connections to this backend. +// Setting this will enable SSL for the connection as a side effect. func (b *BackendOptions) SNIHostname(host string) *BackendOptions { + b.abiOpts.UseSSL(true) b.abiOpts.SNIHostname(host) return b } +// ClientCertificate sets the client certificate to be provided to the server as part of the SSL handshake. +// Setting this will enable SSL for the connection as a side effect. +func (b *BackendOptions) ClientCertificate(certificate string, key secretstore.Secret) *BackendOptions { + b.abiOpts.UseSSL(true) + b.abiOpts.ClientCert(certificate, key.Handle()) + return b +} + +// UseGRPC sets whether or not to connect to the backend via gRPC +func (b *BackendOptions) UseGRPC(v bool) *BackendOptions { + b.abiOpts.UseGRPC(v) + return b +} + // Register a new dynamic backend. func RegisterDynamicBackend(name string, target string, options *BackendOptions) (*Backend, error) { var abiOpts *fastly.BackendConfigOptions diff --git a/internal/abi/fastly/hostcalls_noguest.go b/internal/abi/fastly/hostcalls_noguest.go index bb03ea1..f73e1d2 100644 --- a/internal/abi/fastly/hostcalls_noguest.go +++ b/internal/abi/fastly/hostcalls_noguest.go @@ -352,6 +352,10 @@ func (s *Secret) Plaintext() ([]byte, error) { return nil, fmt.Errorf("not implemented") } +func (s *Secret) Handle() secretHandle { + return 0 +} + func SecretFromBytes(b []byte) (*Secret, error) { return nil, fmt.Errorf("not implemented") } diff --git a/internal/abi/fastly/secret_store_guest.go b/internal/abi/fastly/secret_store_guest.go index 0769c31..901bd07 100644 --- a/internal/abi/fastly/secret_store_guest.go +++ b/internal/abi/fastly/secret_store_guest.go @@ -127,6 +127,10 @@ func (s *Secret) Plaintext() ([]byte, error) { } } +func (s *Secret) Handle() secretHandle { + return s.h +} + // witx: // // (@interface func (export "from_bytes") diff --git a/internal/abi/fastly/types.go b/internal/abi/fastly/types.go index 8b2d517..185b453 100644 --- a/internal/abi/fastly/types.go +++ b/internal/abi/fastly/types.go @@ -730,6 +730,8 @@ const ( backendConfigOptionsMaskCiphers backendConfigOptionsMask = 1 << 10 // $ciphers backendConfigOptionsMaskSNIHostname backendConfigOptionsMask = 1 << 11 // $sni_hostame backendConfigOptionsMaskDontPool backendConfigOptionsMask = 1 << 12 // $dont_pool + backendConfigOptionsMaskClientCert backendConfigOptionsMask = 1 << 13 // $client_cert + backendConfigOptionsMaskGRPC backendConfigOptionsMask = 1 << 14 // $grpc ) // witx: @@ -751,6 +753,9 @@ const ( // (field $ciphers_len u32) // (field $sni_hostname (@witx pointer (@witx char8))) // (field $sni_hostname_len u32) +// (field $client_certificate (@witx pointer (@witx char8))) +// (field $client_certificate_len u32) +// (field $client_key $secret_handle) // )) type backendConfigOptions struct { @@ -769,6 +774,9 @@ type backendConfigOptions struct { ciphersLen prim.U32 sniHostnamePtr prim.Pointer[prim.Char8] sniHostnameLen prim.U32 + clientCertPtr prim.Pointer[prim.Char8] + clientCertLen prim.U32 + clientCertKey secretHandle } // witx: @@ -876,6 +884,22 @@ func (b *BackendConfigOptions) SNIHostname(sniHostname string) { b.opts.sniHostnameLen = prim.U32(buf.Len()) } +func (b *BackendConfigOptions) ClientCert(certificate string, key *Secret) { + b.mask |= backendConfigOptionsMaskClientCert + buf := prim.NewReadBufferFromString(certificate) + b.opts.clientCertPtr = prim.ToPointer(buf.Char8Pointer()) + b.opts.clientCertLen = prim.U32(buf.Len()) + b.opts.clientCertKey = key.Handle() +} + +func (b *BackendConfigOptions) UseGRPC(v bool) { + if v { + b.mask |= backendConfigOptionsMaskGRPC + } else { + b.mask &^= backendConfigOptionsMaskGRPC + } +} + // witx: // // (typename $send_error_detail_tag diff --git a/secretstore/secretstore.go b/secretstore/secretstore.go index cd78e89..7291745 100644 --- a/secretstore/secretstore.go +++ b/secretstore/secretstore.go @@ -102,6 +102,13 @@ func (s *Secret) Plaintext() ([]byte, error) { return plaintext, nil } +// Handle returns an opaque pointer for other packages which need a Secret. +// +// This should not be needed by user code. +func (s *Secret) Handle() *fastly.Secret { + return s.s +} + // FromBytes creates an instance of the [Secret] type for use with APIs // that require it from the provided byte slice. //