Fix Grype CVEs: update logrus and prometheus/prometheus

- Update github.com/sirupsen/logrus v1.9.0 -> v1.9.3 in test/go.mod
  to fix GHSA-4f99-4q7p-p3gh (High)
- Update github.com/prometheus/prometheus v0.35.0 -> v0.311.3
  to fix GHSA-vffh-x6r8-xx99 (Medium)
- Run go mod tidy and go mod vendor to update vendor directory
This commit is contained in:
Bruno Chauvet
2026-05-03 10:05:37 -04:00
parent 45979bdf4e
commit 877b6d6908
279 changed files with 17765 additions and 29131 deletions
+23 -2
View File
@@ -1,3 +1,26 @@
# Changes
## [0.18.2](https://github.com/googleapis/google-cloud-go/releases/tag/auth%2Fv0.18.2) (2026-02-13)
### Bug Fixes
* fixes gdch credentials logic (#13741) ([f82cda5](https://github.com/googleapis/google-cloud-go/commit/f82cda58bd9885b7b8a9d8b15126f5a1e0add0dc))
## [0.18.1](https://github.com/googleapis/google-cloud-go/releases/tag/auth%2Fv0.18.1) (2026-01-21)
### Bug Fixes
* add InternalOptions.TelemetryAttributes for internal client use (#13641) ([3876978](https://github.com/googleapis/google-cloud-go/commit/38769789755ed47d85e85dcd56596109de65f780))
* remove singleton and restore normal usage of otelgrpc.clientHandler (#13522) ([673d4b0](https://github.com/googleapis/google-cloud-go/commit/673d4b05617f833aa433f7f6a350b5cb888ea20d))
## [0.18.0](https://github.com/googleapis/google-cloud-go/releases/tag/auth%2Fv0.18.0) (2025-12-15)
### Features
* Support scopes field from impersonated credential json (#13308) ([e3f62e1](https://github.com/googleapis/google-cloud-go/commit/e3f62e102840127a0058f5cced4c9738f2bf45f2))
* add support for parsing EC private key (#13317) ([ea6bc62](https://github.com/googleapis/google-cloud-go/commit/ea6bc62ffe2cc0a6d607d698a181b37fa46c340d))
* deprecate unsafe credentials JSON loading options (#13397) ([0dd2a3b](https://github.com/googleapis/google-cloud-go/commit/0dd2a3bdece9a85ee7216a737559fa9f5a869545))
## [0.17.0](https://github.com/googleapis/google-cloud-go/releases/tag/auth%2Fv0.17.0) (2025-10-02)
### Features
@@ -5,8 +28,6 @@
* Add trust boundary support for service accounts and impersonation (HTTP/gRPC) (#11870) ([5c2b665](https://github.com/googleapis/google-cloud-go/commit/5c2b665f392e6dd90192f107188720aa1357e7da))
* add trust boundary support for external accounts (#12864) ([a67a146](https://github.com/googleapis/google-cloud-go/commit/a67a146a6a88a6f1ba10c409dfce8015ecd60a64))
# Changelog
## [0.16.5](https://github.com/googleapis/google-cloud-go/compare/auth/v0.16.4...auth/v0.16.5) (2025-08-14)
+151 -14
View File
@@ -52,6 +52,44 @@ var (
allowOnGCECheck = true
)
// CredType specifies the type of JSON credentials being provided
// to a loading function such as [NewCredentialsFromFile] or
// [NewCredentialsFromJSON].
type CredType string
const (
// ServiceAccount represents a service account file type.
ServiceAccount CredType = "service_account"
// AuthorizedUser represents a user credentials file type.
AuthorizedUser CredType = "authorized_user"
// ExternalAccount represents an external account file type.
//
// IMPORTANT:
// This credential type does not validate the credential configuration. A security
// risk occurs when a credential configuration configured with malicious urls
// is used.
// You should validate credential configurations provided by untrusted sources.
// See [Security requirements when using credential configurations from an external
// source] https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
// for more details.
ExternalAccount CredType = "external_account"
// ImpersonatedServiceAccount represents an impersonated service account file type.
//
// IMPORTANT:
// This credential type does not validate the credential configuration. A security
// risk occurs when a credential configuration configured with malicious urls
// is used.
// You should validate credential configurations provided by untrusted sources.
// See [Security requirements when using credential configurations from an external
// source] https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
// for more details.
ImpersonatedServiceAccount CredType = "impersonated_service_account"
// GDCHServiceAccount represents a GDCH service account credentials.
GDCHServiceAccount CredType = "gdch_service_account"
// ExternalAccountAuthorizedUser represents an external account authorized user credentials.
ExternalAccountAuthorizedUser CredType = "external_account_authorized_user"
)
// TokenBindingType specifies the type of binding used when requesting a token
// whether to request a hard-bound token using mTLS or an instance identity
// bound token using ALTS.
@@ -92,6 +130,14 @@ func OnGCE() bool {
// - On Google Compute Engine, Google App Engine standard second generation
// runtimes, and Google App Engine flexible environment, it fetches
// credentials from the metadata server.
//
// Important: If you accept a credential configuration (credential
// JSON/File/Stream) from an external source for authentication to Google
// Cloud Platform, you must validate it before providing it to any Google
// API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For
// more information, refer to [Validate credential configurations from
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
func DetectDefault(opts *DetectOptions) (*auth.Credentials, error) {
if err := opts.validate(); err != nil {
return nil, err
@@ -189,25 +235,61 @@ type DetectOptions struct {
// from the provided filepath. If provided, CredentialsJSON must not be.
// Optional.
//
// Important: If you accept a credential configuration (credential
// JSON/File/Stream) from an external source for authentication to Google
// Cloud Platform, you must validate it before providing it to any Google
// API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For
// more information, refer to [Validate credential configurations from
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
// Deprecated: This field is deprecated because of a potential security risk.
// It does not validate the credential configuration. The security risk occurs
// when a credential configuration is accepted from a source that is not
// under your control and used without validation on your side.
//
// If you know that you will be loading credential configurations of a
// specific type, it is recommended to use a credential-type-specific
// NewCredentialsFromFile method. This will ensure that an unexpected
// credential type with potential for malicious intent is not loaded
// unintentionally. You might still have to do validation for certain
// credential types. Please follow the recommendation for that method. For
// example, if you want to load only service accounts, you can use
//
// creds, err := credentials.NewCredentialsFromFile(ctx, credentials.ServiceAccount, filename, opts)
//
// If you are loading your credential configuration from an untrusted source
// and have not mitigated the risks (e.g. by validating the configuration
// yourself), make these changes as soon as possible to prevent security
// risks to your environment.
//
// Regardless of the method used, it is always your responsibility to
// validate configurations received from external sources.
//
// For more details see:
// https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
CredentialsFile string
// CredentialsJSON overrides detection logic and uses the JSON bytes as the
// source for the credential. If provided, CredentialsFile must not be.
// Optional.
//
// Important: If you accept a credential configuration (credential
// JSON/File/Stream) from an external source for authentication to Google
// Cloud Platform, you must validate it before providing it to any Google
// API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For
// more information, refer to [Validate credential configurations from
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
// Deprecated: This field is deprecated because of a potential security risk.
// It does not validate the credential configuration. The security risk occurs
// when a credential configuration is accepted from a source that is not
// under your control and used without validation on your side.
//
// If you know that you will be loading credential configurations of a
// specific type, it is recommended to use a credential-type-specific
// NewCredentialsFromJSON method. This will ensure that an unexpected
// credential type with potential for malicious intent is not loaded
// unintentionally. You might still have to do validation for certain
// credential types. Please follow the recommendation for that method. For
// example, if you want to load only service accounts, you can use
//
// creds, err := credentials.NewCredentialsFromJSON(ctx, credentials.ServiceAccount, json, opts)
//
// If you are loading your credential configuration from an untrusted source
// and have not mitigated the risks (e.g. by validating the configuration
// yourself), make these changes as soon as possible to prevent security
// risks to your environment.
//
// Regardless of the method used, it is always your responsibility to
// validate configurations received from external sources.
//
// For more details see:
// https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
CredentialsJSON []byte
// UseSelfSignedJWT directs service account based credentials to create a
// self-signed JWT with the private key found in the file, skipping any
@@ -227,6 +309,61 @@ type DetectOptions struct {
Logger *slog.Logger
}
// NewCredentialsFromFile creates a [cloud.google.com/go/auth.Credentials] from
// the provided file. The credType argument specifies the expected credential
// type. If the file content does not match the expected type, an error is
// returned.
//
// Important: If you accept a credential configuration (credential
// JSON/File/Stream) from an external source for authentication to Google
// Cloud Platform, you must validate it before providing it to any Google
// API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For
// more information, refer to [Validate credential configurations from
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
func NewCredentialsFromFile(credType CredType, filename string, opts *DetectOptions) (*auth.Credentials, error) {
b, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
return NewCredentialsFromJSON(credType, b, opts)
}
// NewCredentialsFromJSON creates a [cloud.google.com/go/auth.Credentials] from
// the provided JSON bytes. The credType argument specifies the expected
// credential type. If the JSON does not match the expected type, an error is
// returned.
//
// Important: If you accept a credential configuration (credential
// JSON/File/Stream) from an external source for authentication to Google
// Cloud Platform, you must validate it before providing it to any Google
// API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For
// more information, refer to [Validate credential configurations from
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
func NewCredentialsFromJSON(credType CredType, b []byte, opts *DetectOptions) (*auth.Credentials, error) {
if err := checkCredentialType(b, credType); err != nil {
return nil, err
}
// We can't use readCredentialsFileJSON because it does auto-detection
// for client_credentials.json which we don't support here (no type field).
// Instead, we call fileCredentials just as readCredentialsFileJSON does
// when it doesn't detect client_credentials.json.
return fileCredentials(b, opts)
}
func checkCredentialType(b []byte, expected CredType) error {
fileType, err := credsfile.ParseFileType(b)
if err != nil {
return err
}
if CredType(fileType) != expected {
return fmt.Errorf("credentials: expected type %q, found %q", expected, fileType)
}
return nil
}
func (o *DetectOptions) validate() error {
if o == nil {
return errors.New("credentials: options must be provided")
+24 -11
View File
@@ -28,18 +28,21 @@ import (
"cloud.google.com/go/auth/internal/trustboundary"
)
const cloudPlatformScope = "https://www.googleapis.com/auth/cloud-platform"
func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
fileType, err := credsfile.ParseFileType(b)
if err != nil {
return nil, err
}
if fileType == "" {
return nil, errors.New("credentials: unsupported unidentified file type")
}
var projectID, universeDomain string
var tp auth.TokenProvider
switch fileType {
case credsfile.UnknownCredType:
return nil, errors.New("credentials: unsupported unidentified file type")
case credsfile.ServiceAccountKey:
switch CredType(fileType) {
case ServiceAccount:
f, err := credsfile.ParseServiceAccount(b)
if err != nil {
return nil, err
@@ -50,7 +53,7 @@ func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
}
projectID = f.ProjectID
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
case credsfile.UserCredentialsKey:
case AuthorizedUser:
f, err := credsfile.ParseUserCredentials(b)
if err != nil {
return nil, err
@@ -60,7 +63,7 @@ func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
return nil, err
}
universeDomain = f.UniverseDomain
case credsfile.ExternalAccountKey:
case ExternalAccount:
f, err := credsfile.ParseExternalAccount(b)
if err != nil {
return nil, err
@@ -70,7 +73,7 @@ func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
return nil, err
}
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
case credsfile.ExternalAccountAuthorizedUserKey:
case ExternalAccountAuthorizedUser:
f, err := credsfile.ParseExternalAccountAuthorizedUser(b)
if err != nil {
return nil, err
@@ -80,7 +83,7 @@ func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
return nil, err
}
universeDomain = f.UniverseDomain
case credsfile.ImpersonatedServiceAccountKey:
case ImpersonatedServiceAccount:
f, err := credsfile.ParseImpersonatedServiceAccount(b)
if err != nil {
return nil, err
@@ -90,7 +93,7 @@ func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
return nil, err
}
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
case credsfile.GDCHServiceAccountKey:
case GDCHServiceAccount:
f, err := credsfile.ParseGDCHServiceAccount(b)
if err != nil {
return nil, err
@@ -275,14 +278,24 @@ func handleImpersonatedServiceAccount(f *credsfile.ImpersonatedServiceAccountFil
return nil, errors.New("missing 'source_credentials' field or 'service_account_impersonation_url' in credentials")
}
sourceTP, err := fileCredentials(f.CredSource, opts)
sourceOpts := *opts
// Source credential needs IAM or Cloud Platform scope to call the
// iamcredentials endpoint. The scopes provided by the user are for the
// impersonated credentials.
sourceOpts.Scopes = []string{cloudPlatformScope}
sourceTP, err := fileCredentials(f.CredSource, &sourceOpts)
if err != nil {
return nil, err
}
ud := resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
scopes := opts.scopes()
if len(scopes) == 0 {
scopes = f.Scopes
}
impOpts := &impersonate.Options{
URL: f.ServiceAccountImpersonationURL,
Scopes: opts.scopes(),
Scopes: scopes,
Tp: sourceTP,
Delegates: f.Delegates,
Client: opts.client(),
+20 -13
View File
@@ -15,6 +15,7 @@
package gdch
import (
"bytes"
"context"
"crypto"
"crypto/tls"
@@ -24,9 +25,7 @@ import (
"fmt"
"log/slog"
"net/http"
"net/url"
"os"
"strings"
"time"
"cloud.google.com/go/auth"
@@ -121,27 +120,34 @@ func (g gdchProvider) Token(ctx context.Context) (*auth.Token, error) {
Exp: exp.Unix(),
}
h := jwt.Header{
Algorithm: jwt.HeaderAlgRSA256,
Algorithm: jwt.HeaderAlgES256,
Type: jwt.HeaderType,
KeyID: string(g.pkID),
KeyID: g.pkID,
}
payload, err := jwt.EncodeJWS(&h, &claims, g.signer)
if err != nil {
return nil, err
}
v := url.Values{}
v.Set("grant_type", GrantType)
v.Set("audience", g.aud)
v.Set("requested_token_type", requestTokenType)
v.Set("subject_token", payload)
v.Set("subject_token_type", subjectTokenType)
req, err := http.NewRequestWithContext(ctx, "POST", g.tokenURL, strings.NewReader(v.Encode()))
v := map[string]string{
"grant_type": GrantType,
"audience": g.aud,
"requested_token_type": requestTokenType,
"subject_token": payload,
"subject_token_type": subjectTokenType,
}
r, err := json.Marshal(v)
if err != nil {
return nil, fmt.Errorf("credentials: cannot marshal token request: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", g.tokenURL, bytes.NewReader(r))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
g.logger.DebugContext(ctx, "gdch token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
req.Header.Set("Content-Type", "application/json")
g.logger.DebugContext(ctx, "gdch token request", "request", internallog.HTTPRequest(req, r))
resp, body, err := internal.DoRequest(g.client, req)
if err != nil {
return nil, fmt.Errorf("credentials: cannot fetch token: %w", err)
@@ -188,4 +194,5 @@ func addCertToTransport(hc *http.Client, certPool *x509.CertPool) {
trans.TLSClientConfig = &tls.Config{
RootCAs: certPool,
}
hc.Transport = trans
}
+10 -24
View File
@@ -24,7 +24,6 @@ import (
"log/slog"
"net/http"
"os"
"sync"
"cloud.google.com/go/auth"
"cloud.google.com/go/auth/credentials"
@@ -36,7 +35,6 @@ import (
"google.golang.org/grpc"
grpccreds "google.golang.org/grpc/credentials"
grpcinsecure "google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/stats"
)
const (
@@ -54,27 +52,6 @@ var (
timeoutDialerOption grpc.DialOption
)
// otelStatsHandler is a singleton otelgrpc.clientHandler to be used across
// all dial connections to avoid the memory leak documented in
// https://github.com/open-telemetry/opentelemetry-go-contrib/issues/4226
//
// TODO: When this module depends on a version of otelgrpc containing the fix,
// replace this singleton with inline usage for simplicity.
// The fix should be in https://github.com/open-telemetry/opentelemetry-go/pull/5797.
var (
initOtelStatsHandlerOnce sync.Once
otelStatsHandler stats.Handler
)
// otelGRPCStatsHandler returns singleton otelStatsHandler for reuse across all
// dial connections.
func otelGRPCStatsHandler() stats.Handler {
initOtelStatsHandlerOnce.Do(func() {
otelStatsHandler = otelgrpc.NewClientHandler()
})
return otelStatsHandler
}
// ClientCertProvider is a function that returns a TLS client certificate to be
// used when opening TLS connections. It follows the same semantics as
// [crypto/tls.Config.GetClientCertificate].
@@ -223,6 +200,15 @@ type InternalOptions struct {
// SkipValidation bypasses validation on Options. It should only be used
// internally for clients that needs more control over their transport.
SkipValidation bool
// TelemetryAttributes specifies a map of telemetry attributes to be added
// to all OpenTelemetry signals, such as tracing and metrics, for purposes
// including representing the static identity of the client (e.g., service
// name, version). These attributes are expected to be consistent across all
// signals to enable cross-signal correlation.
//
// It should only be used internally by generated clients. Callers should not
// modify the map after it is passed in.
TelemetryAttributes map[string]string
}
// Dial returns a GRPCClientConnPool that can be used to communicate with a
@@ -444,5 +430,5 @@ func addOpenTelemetryStatsHandler(dialOpts []grpc.DialOption, opts *Options) []g
if opts.DisableTelemetry {
return dialOpts
}
return append(dialOpts, grpc.WithStatsHandler(otelGRPCStatsHandler()))
return append(dialOpts, grpc.WithStatsHandler(otelgrpc.NewClientHandler()))
}
+9
View File
@@ -168,6 +168,15 @@ type InternalOptions struct {
// for the credentials. It should only be used internally for clients that
// need more control over their transport. The default is false.
SkipUniverseDomainValidation bool
// TelemetryAttributes specifies a map of telemetry attributes to be added
// to all OpenTelemetry signals, such as tracing and metrics, for purposes
// including representing the static identity of the client (e.g., service
// name, version). These attributes are expected to be consistent across all
// signals to enable cross-signal correlation.
//
// It should only be used internally by generated clients. Callers should not
// modify the map after it is passed in.
TelemetryAttributes map[string]string
}
// AddAuthorizationMiddleware adds a middleware to the provided client's
-44
View File
@@ -32,50 +32,6 @@ const (
userCredsFilename = "application_default_credentials.json"
)
// CredentialType represents different credential filetypes Google credentials
// can be.
type CredentialType int
const (
// UnknownCredType is an unidentified file type.
UnknownCredType CredentialType = iota
// UserCredentialsKey represents a user creds file type.
UserCredentialsKey
// ServiceAccountKey represents a service account file type.
ServiceAccountKey
// ImpersonatedServiceAccountKey represents a impersonated service account
// file type.
ImpersonatedServiceAccountKey
// ExternalAccountKey represents a external account file type.
ExternalAccountKey
// GDCHServiceAccountKey represents a GDCH file type.
GDCHServiceAccountKey
// ExternalAccountAuthorizedUserKey represents a external account authorized
// user file type.
ExternalAccountAuthorizedUserKey
)
// parseCredentialType returns the associated filetype based on the parsed
// typeString provided.
func parseCredentialType(typeString string) CredentialType {
switch typeString {
case "service_account":
return ServiceAccountKey
case "authorized_user":
return UserCredentialsKey
case "impersonated_service_account":
return ImpersonatedServiceAccountKey
case "external_account":
return ExternalAccountKey
case "external_account_authorized_user":
return ExternalAccountAuthorizedUserKey
case "gdch_service_account":
return GDCHServiceAccountKey
default:
return UnknownCredType
}
}
// GetFileNameFromEnv returns the override if provided or detects a filename
// from the environment.
func GetFileNameFromEnv(override string) string {
+1
View File
@@ -140,6 +140,7 @@ type ImpersonatedServiceAccountFile struct {
Type string `json:"type"`
ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"`
Delegates []string `json:"delegates"`
Scopes []string `json:"scopes"`
CredSource json.RawMessage `json:"source_credentials"`
UniverseDomain string `json:"universe_domain"`
}
+4 -3
View File
@@ -89,10 +89,11 @@ type fileTypeChecker struct {
}
// ParseFileType determines the [CredentialType] based on bytes provided.
func ParseFileType(b []byte) (CredentialType, error) {
// Only returns error for json.Unmarshal.
func ParseFileType(b []byte) (string, error) {
var f fileTypeChecker
if err := json.Unmarshal(b, &f); err != nil {
return 0, err
return "", err
}
return parseCredentialType(f.Type), nil
return f.Type, nil
}
+7 -6
View File
@@ -88,12 +88,13 @@ func ParseKey(key []byte) (crypto.Signer, error) {
key = block.Bytes
}
var parsedKey crypto.PrivateKey
var err error
parsedKey, err = x509.ParsePKCS8PrivateKey(key)
if err != nil {
parsedKey, err = x509.ParsePKCS1PrivateKey(key)
if err != nil {
return nil, fmt.Errorf("private key should be a PEM or plain PKCS1 or PKCS8: %w", err)
var errPKCS8, errPKCS1, errEC error
if parsedKey, errPKCS8 = x509.ParsePKCS8PrivateKey(key); errPKCS8 != nil {
if parsedKey, errPKCS1 = x509.ParsePKCS1PrivateKey(key); errPKCS1 != nil {
if parsedKey, errEC = x509.ParseECPrivateKey(key); errEC != nil {
return nil, fmt.Errorf("failed to parse private key. Tried PKCS8, PKCS1, and EC formats. Errors: [PKCS8: %v], [PKCS1: %v], [EC: %v]", errPKCS8, errPKCS1, errEC)
}
}
}
parsed, ok := parsedKey.(crypto.Signer)
+39 -2
View File
@@ -17,13 +17,16 @@ package jwt
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/asn1"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"math/big"
"strings"
"time"
)
@@ -35,6 +38,8 @@ const (
HeaderAlgES256 = "ES256"
// HeaderType is the standard [Header.Type].
HeaderType = "JWT"
// ES256 key size
es256KeySize = 32
)
// Header represents a JWT header.
@@ -127,6 +132,22 @@ func EncodeJWS(header *Header, c *Claims, signer crypto.Signer) (string, error)
if err != nil {
return "", err
}
if header.Algorithm == HeaderAlgES256 {
var ecSig struct {
R, S *big.Int
}
if _, err := asn1.Unmarshal(sig, &ecSig); err != nil {
return "", err
}
rawSig := make([]byte, es256KeySize*2)
ecSig.R.FillBytes(rawSig[:es256KeySize])
ecSig.S.FillBytes(rawSig[es256KeySize:])
sig = rawSig
}
return fmt.Sprintf("%s.%s", ss, base64.RawURLEncoding.EncodeToString(sig)), nil
}
@@ -153,7 +174,7 @@ func DecodeJWS(payload string) (*Claims, error) {
// VerifyJWS tests whether the provided JWT token's signature was produced by
// the private key associated with the provided public key.
func VerifyJWS(token string, key *rsa.PublicKey) error {
func VerifyJWS(token string, key crypto.PublicKey) error {
parts := strings.Split(token, ".")
if len(parts) != 3 {
return errors.New("jwt: invalid token received, token must have 3 parts")
@@ -167,5 +188,21 @@ func VerifyJWS(token string, key *rsa.PublicKey) error {
h := sha256.New()
h.Write([]byte(signedContent))
return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), signatureString)
hashed := h.Sum(nil)
switch pub := key.(type) {
case *rsa.PublicKey:
return rsa.VerifyPKCS1v15(pub, crypto.SHA256, hashed, signatureString)
case *ecdsa.PublicKey:
if len(signatureString) != 2*32 {
return fmt.Errorf("jwt: ecdsa signature size should be 64 bytes, got %d", len(signatureString))
}
r := new(big.Int).SetBytes(signatureString[:32])
s := new(big.Int).SetBytes(signatureString[32:])
if !ecdsa.Verify(pub, hashed, r, s) {
return errors.New("jwt: ecdsa signature verification failed")
}
return nil
}
return fmt.Errorf("jwt: unsupported public key type: %T", key)
}
+2 -2
View File
@@ -1,4 +1,4 @@
// Copyright 2025 Google LLC
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -17,4 +17,4 @@
package internal
// Version is the current tagged release of the library.
const Version = "0.17.0"
const Version = "0.18.2"