From 3ab4c5803be67440a89a6424bb1463ab43a59322 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Wed, 11 Mar 2026 15:49:06 -0700 Subject: [PATCH 1/2] internal,fsthttp: fix broken API for DownstreamTLSClientCertVerifyResult() Previously this hostcall was marked as returning a bool, but it actually returns an enum. --- fsthttp/request.go | 35 ++++++++++++++++++++++-- internal/abi/fastly/hostcalls_noguest.go | 4 +-- internal/abi/fastly/http_guest.go | 10 +++---- internal/abi/fastly/types.go | 33 ++++++++++++++++++++++ 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/fsthttp/request.go b/fsthttp/request.go index 292bde7..986ca44 100644 --- a/fsthttp/request.go +++ b/fsthttp/request.go @@ -1081,7 +1081,7 @@ func (req *Request) TLSClientCertificateInfo() (*TLSClientCertificateInfo, error } if cert.RawClientCertificate != nil { - cert.ClientCertIsVerified, err = req.downstream.req.DownstreamTLSClientCertVerifyResult() + cert.VerifyResult, err = req.downstream.req.DownstreamTLSClientCertVerifyResult() if err != nil { return nil, fmt.Errorf("get TLS client certificate verify: %w", err) } @@ -1092,12 +1092,41 @@ func (req *Request) TLSClientCertificateInfo() (*TLSClientCertificateInfo, error return req.clientCertificate, nil } +type ClientCertificateVerifyResult = fastly.ClientCertificateVerifyResult + +const ( + // ClientCertificateVerifyResultOk indicates that client certificate verified successfully. + ClientCertificateVerifyResultOk = fastly.ClientCertificateVerifyResultOk + + // ClientCertificateVerifyResultBadCertificate means the certificate is corrupt + // (e.g., the certificate signatures do not verify correctly). + ClientCertificateVerifyResultBadCertificate = fastly.ClientCertificateVerifyResultBadCertificate + + // ClientCertificateVerifyResultCertificateRevoked means the client certificate is revoked by its signer. + ClientCertificateVerifyResultCertificateRevoked = fastly.ClientCertificateVerifyResultCertificateRevoked + + // ClientCertificateVerifyResultCertificateExpired means the client certificate has expired or is not currently valid. + ClientCertificateVerifyResultCertificateExpired = fastly.ClientCertificateVerifyResultCertificateExpired + + // ClientCertificateVerifyResultUnknownCa means the valid certificate chain or partial chain was received, but the + // certificate was not accepted because the CA certificate could not be located or could not + // be matched with a known trust anchor. + ClientCertificateVerifyResultUnknownCa = fastly.ClientCertificateVerifyResultUnknownCa + + // ClientCertificateVerifyResultCertificateMissing means the client did not provide a certificate during the handshake. + ClientCertificateVerifyResultCertificateMissing = fastly.ClientCertificateVerifyResultCertificateMissing + + // ClientCertificateVerifyResultCertificateUnknown means the client certificate was received, but some other (unspecified) issue + // arose in processing the certificate, rendering it unacceptable. + ClientCertificateVerifyResultCertificateUnknown = fastly.ClientCertificateVerifyResultCertificateUnknown +) + type TLSClientCertificateInfo struct { // RawClientCertificate contains the bytes of the raw client certificate, if one was provided. RawClientCertificate []byte - // ClientCertIsVerified is true if the provided client certificate is valid. - ClientCertIsVerified bool + // VerifyResult the result of the client certificate verification + VerifyResult ClientCertificateVerifyResult } // FastlyMeta holds various Fastly-specific metadata for a request. diff --git a/internal/abi/fastly/hostcalls_noguest.go b/internal/abi/fastly/hostcalls_noguest.go index 247daa0..337b1d1 100644 --- a/internal/abi/fastly/hostcalls_noguest.go +++ b/internal/abi/fastly/hostcalls_noguest.go @@ -131,8 +131,8 @@ func (r *HTTPRequest) DownstreamTLSRawClientCertificate() ([]byte, error) { return nil, fmt.Errorf("not implemented") } -func (r *HTTPRequest) DownstreamTLSClientCertVerifyResult() (bool, error) { - return false, fmt.Errorf("not implemented") +func (r *HTTPRequest) DownstreamTLSClientCertVerifyResult() (ClientCertificateVerifyResult, error) { + return 0, fmt.Errorf("not implemented") } func (r *HTTPRequest) DownstreamTLSJA4() ([]byte, error) { diff --git a/internal/abi/fastly/http_guest.go b/internal/abi/fastly/http_guest.go index 51a7987..84058b5 100644 --- a/internal/abi/fastly/http_guest.go +++ b/internal/abi/fastly/http_guest.go @@ -1684,19 +1684,19 @@ func (r *HTTPRequest) DownstreamTLSRawClientCertificate() ([]byte, error) { //go:noescape func fastlyHTTPDownstreamTLSClientCertVerifyResult( req requestHandle, - result prim.Pointer[bool], + result prim.Pointer[prim.U32], ) FastlyStatus -func (r *HTTPRequest) DownstreamTLSClientCertVerifyResult() (bool, error) { - var result bool +func (r *HTTPRequest) DownstreamTLSClientCertVerifyResult() (ClientCertificateVerifyResult, error) { + var result prim.U32 if err := fastlyHTTPDownstreamTLSClientCertVerifyResult( r.h, prim.ToPointer(&result), ).toError(); err != nil { - return false, err + return 0, err } - return result, nil + return ClientCertificateVerifyResult(result), nil } // witx: diff --git a/internal/abi/fastly/types.go b/internal/abi/fastly/types.go index b26adf3..ddcdf48 100644 --- a/internal/abi/fastly/types.go +++ b/internal/abi/fastly/types.go @@ -1629,6 +1629,39 @@ func tlsAlertString(id prim.U8) string { } } +type ClientCertificateVerifyResult prim.U32 + +const ( + ClientCertificateVerifyResultOk ClientCertificateVerifyResult = 0 + ClientCertificateVerifyResultBadCertificate ClientCertificateVerifyResult = 1 + ClientCertificateVerifyResultCertificateRevoked ClientCertificateVerifyResult = 2 + ClientCertificateVerifyResultCertificateExpired ClientCertificateVerifyResult = 3 + ClientCertificateVerifyResultUnknownCa ClientCertificateVerifyResult = 4 + ClientCertificateVerifyResultCertificateMissing ClientCertificateVerifyResult = 5 + ClientCertificateVerifyResultCertificateUnknown ClientCertificateVerifyResult = 6 +) + +func (c ClientCertificateVerifyResult) String() string { + switch c { + case 0: + return "Ok" + case 1: + return "Bad Certificate" + case 2: + return "Certificate Revoked" + case 3: + return "Certificate Expired" + case 4: + return "Unknown CA" + case 5: + return "Certificate Missing" + case 6: + return "Certificate Unknown" + } + + return "Unknown result" +} + type RateWindow struct { value prim.U32 } From 96b0d6210861f64fbd4437ce3df152d1e877cd26 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Thu, 12 Mar 2026 08:57:57 -0700 Subject: [PATCH 2/2] internal,fsthttp: fix constant naming: Ca -> CA, Ok -> OK --- fsthttp/request.go | 8 ++++---- internal/abi/fastly/types.go | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fsthttp/request.go b/fsthttp/request.go index 986ca44..2c4908a 100644 --- a/fsthttp/request.go +++ b/fsthttp/request.go @@ -1095,8 +1095,8 @@ func (req *Request) TLSClientCertificateInfo() (*TLSClientCertificateInfo, error type ClientCertificateVerifyResult = fastly.ClientCertificateVerifyResult const ( - // ClientCertificateVerifyResultOk indicates that client certificate verified successfully. - ClientCertificateVerifyResultOk = fastly.ClientCertificateVerifyResultOk + // ClientCertificateVerifyResultOK indicates that client certificate verified successfully. + ClientCertificateVerifyResultOK = fastly.ClientCertificateVerifyResultOK // ClientCertificateVerifyResultBadCertificate means the certificate is corrupt // (e.g., the certificate signatures do not verify correctly). @@ -1108,10 +1108,10 @@ const ( // ClientCertificateVerifyResultCertificateExpired means the client certificate has expired or is not currently valid. ClientCertificateVerifyResultCertificateExpired = fastly.ClientCertificateVerifyResultCertificateExpired - // ClientCertificateVerifyResultUnknownCa means the valid certificate chain or partial chain was received, but the + // ClientCertificateVerifyResultUnknownCA means the valid certificate chain or partial chain was received, but the // certificate was not accepted because the CA certificate could not be located or could not // be matched with a known trust anchor. - ClientCertificateVerifyResultUnknownCa = fastly.ClientCertificateVerifyResultUnknownCa + ClientCertificateVerifyResultUnknownCA = fastly.ClientCertificateVerifyResultUnknownCA // ClientCertificateVerifyResultCertificateMissing means the client did not provide a certificate during the handshake. ClientCertificateVerifyResultCertificateMissing = fastly.ClientCertificateVerifyResultCertificateMissing diff --git a/internal/abi/fastly/types.go b/internal/abi/fastly/types.go index ddcdf48..a41964a 100644 --- a/internal/abi/fastly/types.go +++ b/internal/abi/fastly/types.go @@ -1632,11 +1632,11 @@ func tlsAlertString(id prim.U8) string { type ClientCertificateVerifyResult prim.U32 const ( - ClientCertificateVerifyResultOk ClientCertificateVerifyResult = 0 + ClientCertificateVerifyResultOK ClientCertificateVerifyResult = 0 ClientCertificateVerifyResultBadCertificate ClientCertificateVerifyResult = 1 ClientCertificateVerifyResultCertificateRevoked ClientCertificateVerifyResult = 2 ClientCertificateVerifyResultCertificateExpired ClientCertificateVerifyResult = 3 - ClientCertificateVerifyResultUnknownCa ClientCertificateVerifyResult = 4 + ClientCertificateVerifyResultUnknownCA ClientCertificateVerifyResult = 4 ClientCertificateVerifyResultCertificateMissing ClientCertificateVerifyResult = 5 ClientCertificateVerifyResultCertificateUnknown ClientCertificateVerifyResult = 6 )