mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-11 20:29:00 +00:00
fix: remove unused jwkThumbprint, move verifyJWSSignature to test file
golangci-lint flagged jwkThumbprint as unused. Removed it and the dead var _ compile-time checks. Moved verifyJWSSignature (test-only helper) from profile.go to profile_test.go where it belongs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,19 +2,15 @@ package acme
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
goacme "golang.org/x/crypto/acme"
|
goacme "golang.org/x/crypto/acme"
|
||||||
)
|
)
|
||||||
@@ -254,61 +250,3 @@ func signJWS(key *ecdsa.PrivateKey, kid, nonce, targetURL string, payload []byte
|
|||||||
return json.Marshal(jws)
|
return json.Marshal(jws)
|
||||||
}
|
}
|
||||||
|
|
||||||
// jwkThumbprint computes the JWK thumbprint per RFC 7638 for an ECDSA P-256 key.
|
|
||||||
// This is used for JWK-mode JWS (account creation) but not for kid-mode (existing accounts).
|
|
||||||
// Exported for potential future use; not currently used in the profile flow.
|
|
||||||
func jwkThumbprint(key *ecdsa.PublicKey) (string, error) {
|
|
||||||
if key.Curve != elliptic.P256() {
|
|
||||||
return "", fmt.Errorf("unsupported curve: only P-256 is supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// JWK canonical form for EC keys: {"crv":"P-256","kty":"EC","x":"...","y":"..."}
|
|
||||||
x := base64.RawURLEncoding.EncodeToString(key.X.Bytes())
|
|
||||||
y := base64.RawURLEncoding.EncodeToString(key.Y.Bytes())
|
|
||||||
canonical := fmt.Sprintf(`{"crv":"P-256","kty":"EC","x":"%s","y":"%s"}`, x, y)
|
|
||||||
|
|
||||||
hash := sha256.Sum256([]byte(canonical))
|
|
||||||
return base64.RawURLEncoding.EncodeToString(hash[:]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// verifyJWSSignature is a test helper that verifies a JWS signature.
|
|
||||||
// Only used in tests — not part of the production flow.
|
|
||||||
func verifyJWSSignature(jwsJSON []byte, pubKey *ecdsa.PublicKey) error {
|
|
||||||
var jws struct {
|
|
||||||
Protected string `json:"protected"`
|
|
||||||
Payload string `json:"payload"`
|
|
||||||
Signature string `json:"signature"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(jwsJSON, &jws); err != nil {
|
|
||||||
return fmt.Errorf("unmarshal JWS: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
signingInput := jws.Protected + "." + jws.Payload
|
|
||||||
hash := sha256.Sum256([]byte(signingInput))
|
|
||||||
|
|
||||||
sigBytes, err := base64.RawURLEncoding.DecodeString(jws.Signature)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("decode signature: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
keyBytes := pubKey.Curve.Params().BitSize / 8
|
|
||||||
if len(sigBytes) != 2*keyBytes {
|
|
||||||
return fmt.Errorf("invalid signature length: %d (expected %d)", len(sigBytes), 2*keyBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
r := new(big.Int).SetBytes(sigBytes[:keyBytes])
|
|
||||||
s := new(big.Int).SetBytes(sigBytes[keyBytes:])
|
|
||||||
|
|
||||||
if !ecdsa.Verify(pubKey, hash[:], r, s) {
|
|
||||||
return fmt.Errorf("signature verification failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure crypto.Signer is satisfied (compile-time check, unused at runtime).
|
|
||||||
var _ crypto.Signer = (*ecdsa.PrivateKey)(nil)
|
|
||||||
|
|
||||||
// Ensure time is imported for potential use in NotBefore/NotAfter.
|
|
||||||
var _ = time.Now
|
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ import (
|
|||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"math/big"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
@@ -19,6 +21,41 @@ import (
|
|||||||
goacme "golang.org/x/crypto/acme"
|
goacme "golang.org/x/crypto/acme"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// verifyJWSSignature is a test helper that verifies a JWS signature.
|
||||||
|
func verifyJWSSignature(jwsJSON []byte, pubKey *ecdsa.PublicKey) error {
|
||||||
|
var jws struct {
|
||||||
|
Protected string `json:"protected"`
|
||||||
|
Payload string `json:"payload"`
|
||||||
|
Signature string `json:"signature"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(jwsJSON, &jws); err != nil {
|
||||||
|
return fmt.Errorf("unmarshal JWS: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
signingInput := jws.Protected + "." + jws.Payload
|
||||||
|
hash := sha256.Sum256([]byte(signingInput))
|
||||||
|
|
||||||
|
sigBytes, err := base64.RawURLEncoding.DecodeString(jws.Signature)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decode signature: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
keyBytes := pubKey.Curve.Params().BitSize / 8
|
||||||
|
if len(sigBytes) != 2*keyBytes {
|
||||||
|
return fmt.Errorf("invalid signature length: %d (expected %d)", len(sigBytes), 2*keyBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := new(big.Int).SetBytes(sigBytes[:keyBytes])
|
||||||
|
s := new(big.Int).SetBytes(sigBytes[keyBytes:])
|
||||||
|
|
||||||
|
if !ecdsa.Verify(pubKey, hash[:], r, s) {
|
||||||
|
return fmt.Errorf("signature verification failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestValidateConfig_ProfileValid(t *testing.T) {
|
func TestValidateConfig_ProfileValid(t *testing.T) {
|
||||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|||||||
Reference in New Issue
Block a user