Skip to content

Commit 54731ff

Browse files
committed
Replace jwx with dsig
1 parent ab7fe30 commit 54731ff

File tree

4 files changed

+118
-105
lines changed

4 files changed

+118
-105
lines changed

go.mod

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,14 @@ go 1.24.4
44

55
require (
66
github.com/lestrrat-go/blackmagic v1.0.4
7-
github.com/lestrrat-go/jwx/v3 v3.0.10
7+
github.com/lestrrat-go/dsig v0.0.0-20250811215124-541f079dd525
88
github.com/lestrrat-go/option v1.0.1
99
github.com/lestrrat-go/sfv v0.0.0-20250812055001-7c45bde43af8
1010
github.com/stretchr/testify v1.10.0
1111
)
1212

1313
require (
1414
github.com/davecgh/go-spew v1.1.1 // indirect
15-
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
16-
github.com/goccy/go-json v0.10.5 // indirect
17-
github.com/lestrrat-go/httpcc v1.0.1 // indirect
18-
github.com/lestrrat-go/httprc/v3 v3.0.0 // indirect
19-
github.com/lestrrat-go/option/v2 v2.0.0 // indirect
2015
github.com/pmezard/go-difflib v1.0.0 // indirect
21-
github.com/segmentio/asm v1.2.0 // indirect
22-
github.com/valyala/fastjson v1.6.4 // indirect
23-
golang.org/x/sys v0.35.0 // indirect
2416
gopkg.in/yaml.v3 v3.0.1 // indirect
2517
)

go.sum

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,20 @@
11
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
22
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
33
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4-
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
5-
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
6-
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
7-
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
84
github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA=
95
github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
10-
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
11-
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
12-
github.com/lestrrat-go/httprc/v3 v3.0.0 h1:nZUx/zFg5uc2rhlu1L1DidGr5Sj02JbXvGSpnY4LMrc=
13-
github.com/lestrrat-go/httprc/v3 v3.0.0/go.mod h1:k2U1QIiyVqAKtkffbg+cUmsyiPGQsb9aAfNQiNFuQ9Q=
14-
github.com/lestrrat-go/jwx/v3 v3.0.10 h1:XuoCBhZBncRIjMQ32HdEc76rH0xK/Qv2wq5TBouYJDw=
15-
github.com/lestrrat-go/jwx/v3 v3.0.10/go.mod h1:kNMedLgTpHvPJkK5EMVa1JFz+UVyY2dMmZKu3qjl/Pk=
6+
github.com/lestrrat-go/dsig v0.0.0-20250811215124-541f079dd525 h1:rColmRfuXL89rjosY3LX7DVDhCrV9j95zrFZwOIsr9U=
7+
github.com/lestrrat-go/dsig v0.0.0-20250811215124-541f079dd525/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo=
168
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
179
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
18-
github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss=
19-
github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg=
2010
github.com/lestrrat-go/sfv v0.0.0-20250812055001-7c45bde43af8 h1:S2y/eNSgmIVlg3H/xrvEJKRt/ap041le3khSigbBudA=
2111
github.com/lestrrat-go/sfv v0.0.0-20250812055001-7c45bde43af8/go.mod h1:vuz+hqEIxrAN4liZnvbmAoggJm33TayPqYTwX1xssXQ=
2212
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2313
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
24-
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
25-
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
2614
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
2715
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
28-
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
2916
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
3017
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
31-
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
32-
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
33-
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
34-
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
35-
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
36-
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
3718
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
3819
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
3920
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

htmsig.go

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import (
99
"net/http"
1010
"strings"
1111

12+
"github.com/lestrrat-go/dsig"
1213
"github.com/lestrrat-go/htmsig/component"
1314
"github.com/lestrrat-go/htmsig/input"
14-
"github.com/lestrrat-go/jwx/v3/jws/jwsbb"
1515
"github.com/lestrrat-go/sfv"
1616
)
1717

@@ -198,104 +198,104 @@ func buildSignatureBase(ctx context.Context, def *input.Definition) ([]byte, err
198198

199199
// generateSignature creates a signature over the signature base using the provided key material
200200
// This implements the HTTP_SIGN primitive function from RFC 9421 Section 3.3
201-
// Uses JWX's jwsbb (JWS Bare Bones) for cryptographic signing operations
201+
// Uses DSIG for cryptographic signing operations
202202
func generateSignature(ctx context.Context, sigbase []byte, def *input.Definition, key any) ([]byte, error) {
203-
// Determine the appropriate JWS algorithm, preferring explicit algorithm from Definition
204-
algorithm, err := determineJWSAlgorithm(def, key)
203+
// Determine the appropriate algorithm, preferring explicit algorithm from Definition
204+
algorithm, err := determineAlgorithm(def, key)
205205
if err != nil {
206-
return nil, fmt.Errorf("failed to determine JWS algorithm: %w", err)
206+
return nil, fmt.Errorf("failed to determine algorithm: %w", err)
207207
}
208208

209-
// Use JWX's jwsbb to sign the signature base directly
209+
// Use DSIG to sign the signature base directly
210210
// RFC 9421 Section 3.3.7: "the HTTP message's signature base is used as the entire JWS Signing Input"
211211
// "The JOSE Header is not used, and the signature base is not first encoded in Base64"
212-
signature, err := jwsbb.Sign(key, algorithm, sigbase, nil)
212+
signature, err := dsig.Sign(key, algorithm, sigbase, nil)
213213
if err != nil {
214214
return nil, fmt.Errorf("failed to sign with algorithm %s: %w", algorithm, err)
215215
}
216216

217217
return signature, nil
218218
}
219219

220-
// determineJWSAlgorithm determines the appropriate JWS algorithm from Definition and key material
220+
// determineAlgorithm determines the appropriate algorithm from Definition and key material
221221
// First checks the explicit algorithm parameter in Definition, then falls back to key type detection
222-
func determineJWSAlgorithm(def *input.Definition, key any) (string, error) {
222+
func determineAlgorithm(def *input.Definition, key any) (string, error) {
223223
// First, check if algorithm is explicitly specified in the Definition
224224
if algorithm := def.Algorithm(); algorithm != "" {
225-
// Convert RFC 9421 algorithm names to JWS algorithm names
226-
return convertRFC9421ToJWS(algorithm)
225+
// Convert RFC 9421 algorithm names to DSIG algorithm names
226+
return convertRFC9421ToDSIG(algorithm)
227227
}
228228

229229
// Fallback to determining algorithm from key material
230-
return determineJWSAlgorithmFromKey(key)
230+
return determineAlgorithmFromKey(key)
231231
}
232232

233-
// convertRFC9421ToJWS converts RFC 9421 algorithm names to JWS algorithm identifiers
234-
// Maps the official RFC 9421 algorithm registry entries to their corresponding JWS algorithm names
235-
func convertRFC9421ToJWS(rfc9421Alg string) (string, error) {
233+
// convertRFC9421ToDSIG converts RFC 9421 algorithm names to DSIG algorithm identifiers
234+
// Maps the official RFC 9421 algorithm registry entries to their corresponding DSIG algorithm names
235+
func convertRFC9421ToDSIG(rfc9421Alg string) (string, error) {
236236
switch rfc9421Alg {
237237
// Official RFC 9421 algorithms from Section 6.2.2 Initial Contents
238238
case "rsa-pss-sha512": // Section 3.3.1
239-
return "PS512", nil
239+
return dsig.RSAPSSWithSHA512, nil
240240
case "rsa-v1_5-sha256": // Section 3.3.2
241-
return "RS256", nil
241+
return dsig.RSAPKCS1v15WithSHA256, nil
242242
case "hmac-sha256": // Section 3.3.3
243-
return "HS256", nil
243+
return dsig.HMACWithSHA256, nil
244244
case "ecdsa-p256-sha256": // Section 3.3.4
245-
return "ES256", nil
245+
return dsig.ECDSAWithP256AndSHA256, nil
246246
case "ecdsa-p384-sha384": // Section 3.3.5
247-
return "ES384", nil
247+
return dsig.ECDSAWithP384AndSHA384, nil
248248
case "ed25519": // Section 3.3.6
249-
return "EdDSA", nil
249+
return dsig.EdDSA, nil
250250
default:
251251
return "", fmt.Errorf("unsupported RFC 9421 algorithm: %s", rfc9421Alg)
252252
}
253253
}
254254

255-
// determineJWSAlgorithmFromKey determines the appropriate JWS algorithm from key material
256-
// Maps key types to JWS algorithm identifiers for use with jwsbb
257-
func determineJWSAlgorithmFromKey(key any) (string, error) {
255+
// determineAlgorithmFromKey determines the appropriate DSIG algorithm from key material
256+
// Maps key types to DSIG algorithm identifiers
257+
func determineAlgorithmFromKey(key any) (string, error) {
258258
switch k := key.(type) {
259259
case *rsa.PrivateKey:
260-
// Use PS512 (RSA-PSS with SHA-512) as per RFC 9421 Section 3.3.1
261-
return "PS512", nil
260+
// Use RSA-PSS with SHA-512 as per RFC 9421 Section 3.3.1
261+
return dsig.RSAPSSWithSHA512, nil
262262
case *rsa.PublicKey:
263-
// Use PS512 (RSA-PSS with SHA-512) for public key verification
264-
return "PS512", nil
263+
// Use RSA-PSS with SHA-512 for public key verification
264+
return dsig.RSAPSSWithSHA512, nil
265265
case *ecdsa.PrivateKey:
266266
// Determine curve and select appropriate ECDSA algorithm
267267
switch k.Curve.Params().Name {
268268
case "P-256":
269-
// ES256 (ECDSA using P-256 and SHA-256) as per RFC 9421 Section 3.3.4
270-
return "ES256", nil
269+
// ECDSA using P-256 and SHA-256 as per RFC 9421 Section 3.3.4
270+
return dsig.ECDSAWithP256AndSHA256, nil
271271
case "P-384":
272-
// ES384 (ECDSA using P-384 and SHA-384) as per RFC 9421 Section 3.3.5
273-
return "ES384", nil
272+
// ECDSA using P-384 and SHA-384 as per RFC 9421 Section 3.3.5
273+
return dsig.ECDSAWithP384AndSHA384, nil
274274
default:
275275
return "", fmt.Errorf("unsupported ECDSA curve: %s", k.Curve.Params().Name)
276276
}
277277
case *ecdsa.PublicKey:
278278
// Determine curve and select appropriate ECDSA algorithm for public key
279279
switch k.Curve.Params().Name {
280280
case "P-256":
281-
return "ES256", nil
281+
return dsig.ECDSAWithP256AndSHA256, nil
282282
case "P-384":
283-
return "ES384", nil
283+
return dsig.ECDSAWithP384AndSHA384, nil
284284
default:
285285
return "", fmt.Errorf("unsupported ECDSA curve: %s", k.Curve.Params().Name)
286286
}
287287
case ed25519.PrivateKey:
288288
// EdDSA using Ed25519 as per RFC 9421 Section 3.3.6
289-
return "EdDSA", nil
289+
return dsig.EdDSA, nil
290290
case ed25519.PublicKey:
291291
// EdDSA using Ed25519 for public key verification
292-
return "EdDSA", nil
292+
return dsig.EdDSA, nil
293293
case []byte:
294-
// HS256 (HMAC using SHA-256) for raw byte keys as per RFC 9421 Section 3.3.3
295-
return "HS256", nil
294+
// HMAC using SHA-256 for raw byte keys as per RFC 9421 Section 3.3.3
295+
return dsig.HMACWithSHA256, nil
296296
case string:
297-
// HS256 (HMAC using SHA-256) for string keys as per RFC 9421 Section 3.3.3
298-
return "HS256", nil
297+
// HMAC using SHA-256 for string keys as per RFC 9421 Section 3.3.3
298+
return dsig.HMACWithSHA256, nil
299299
default:
300300
return "", fmt.Errorf("unsupported key type: %T", key)
301301
}
@@ -410,18 +410,18 @@ func resolveKey(keyOrResolver any, def *input.Definition) (any, error) {
410410
}
411411

412412
// verifySignature verifies a single signature using the HTTP_VERIFY primitive from RFC 9421 Section 3.3
413-
// Uses JWX's jwsbb for cryptographic verification operations
413+
// Uses DSIG for cryptographic verification operations
414414
func verifySignature(_ context.Context, signatureBase []byte, signatureBytes []byte, def *input.Definition, key any) error {
415-
// Determine the appropriate JWS algorithm, preferring explicit algorithm from Definition
416-
algorithm, err := determineJWSAlgorithm(def, key)
415+
// Determine the appropriate algorithm, preferring explicit algorithm from Definition
416+
algorithm, err := determineAlgorithm(def, key)
417417
if err != nil {
418-
return fmt.Errorf("failed to determine JWS algorithm: %w", err)
418+
return fmt.Errorf("failed to determine algorithm: %w", err)
419419
}
420420

421-
// Use JWX's jwsbb to verify the signature directly
421+
// Use DSIG to verify the signature directly
422422
// RFC 9421 Section 3.3.7: "the HTTP message's signature base is used as the entire JWS Signing Input"
423423
// "The JOSE Header is not used, and the signature base is not first encoded in Base64"
424-
err = jwsbb.Verify(key, algorithm, signatureBase, signatureBytes)
424+
err = dsig.Verify(key, algorithm, signatureBase, signatureBytes)
425425
if err != nil {
426426
return fmt.Errorf("cryptographic verification failed with algorithm %s: %w", algorithm, err)
427427
}

rfc9421_test.go

Lines changed: 69 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import (
55
"crypto/ecdsa"
66
"crypto/ed25519"
77
"crypto/rsa"
8+
"crypto/x509"
89
"encoding/base64"
10+
"encoding/pem"
911
"fmt"
1012
"net/http"
1113
"net/http/httptest"
@@ -16,7 +18,6 @@ import (
1618
"github.com/lestrrat-go/htmsig"
1719
"github.com/lestrrat-go/htmsig/component"
1820
"github.com/lestrrat-go/htmsig/input"
19-
"github.com/lestrrat-go/jwx/v3/jwk"
2021
"github.com/stretchr/testify/require"
2122
)
2223

@@ -129,28 +130,50 @@ func createTestResponse(req *http.Request) *http.Response {
129130

130131
// parsePrivateKey parses a PEM private key and returns the appropriate type
131132
func parsePrivateKey(pemData string, keyType string) (any, error) {
132-
key, err := jwk.ParseKey([]byte(pemData), jwk.WithPEM(true))
133-
if err != nil {
134-
return nil, err
133+
block, _ := pem.Decode([]byte(pemData))
134+
if block == nil {
135+
return nil, fmt.Errorf("failed to decode PEM block")
135136
}
136137

137138
switch keyType {
138139
case "rsa", "rsa-pss":
139-
var rsaKey rsa.PrivateKey
140-
if err := jwk.Export(key, &rsaKey); err != nil {
141-
return nil, err
140+
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
141+
if err != nil {
142+
// Try PKCS8 format
143+
keyIface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
144+
if err != nil {
145+
return nil, fmt.Errorf("failed to parse RSA private key: %w", err)
146+
}
147+
rsaKey, ok := keyIface.(*rsa.PrivateKey)
148+
if !ok {
149+
return nil, fmt.Errorf("expected RSA private key, got %T", keyIface)
150+
}
151+
return rsaKey, nil
142152
}
143-
return &rsaKey, nil
153+
return key, nil
144154
case "ecdsa":
145-
var ecKey ecdsa.PrivateKey
146-
if err := jwk.Export(key, &ecKey); err != nil {
147-
return nil, err
155+
key, err := x509.ParseECPrivateKey(block.Bytes)
156+
if err != nil {
157+
// Try PKCS8 format
158+
keyIface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
159+
if err != nil {
160+
return nil, fmt.Errorf("failed to parse ECDSA private key: %w", err)
161+
}
162+
ecKey, ok := keyIface.(*ecdsa.PrivateKey)
163+
if !ok {
164+
return nil, fmt.Errorf("expected ECDSA private key, got %T", keyIface)
165+
}
166+
return ecKey, nil
148167
}
149-
return &ecKey, nil
168+
return key, nil
150169
case "ed25519":
151-
var edKey ed25519.PrivateKey
152-
if err := jwk.Export(key, &edKey); err != nil {
153-
return nil, err
170+
keyIface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
171+
if err != nil {
172+
return nil, fmt.Errorf("failed to parse Ed25519 private key: %w", err)
173+
}
174+
edKey, ok := keyIface.(ed25519.PrivateKey)
175+
if !ok {
176+
return nil, fmt.Errorf("expected Ed25519 private key, got %T", keyIface)
154177
}
155178
return edKey, nil
156179
default:
@@ -160,28 +183,45 @@ func parsePrivateKey(pemData string, keyType string) (any, error) {
160183

161184
// parsePublicKey parses a PEM public key and returns the appropriate type
162185
func parsePublicKey(pemData string, keyType string) (any, error) {
163-
key, err := jwk.ParseKey([]byte(pemData), jwk.WithPEM(true))
164-
if err != nil {
165-
return nil, err
186+
block, _ := pem.Decode([]byte(pemData))
187+
if block == nil {
188+
return nil, fmt.Errorf("failed to decode PEM block")
166189
}
167190

168191
switch keyType {
169192
case "rsa", "rsa-pss":
170-
var rsaKey rsa.PublicKey
171-
if err := jwk.Export(key, &rsaKey); err != nil {
172-
return nil, err
193+
key, err := x509.ParsePKCS1PublicKey(block.Bytes)
194+
if err != nil {
195+
// Try PKIX format
196+
keyIface, err := x509.ParsePKIXPublicKey(block.Bytes)
197+
if err != nil {
198+
return nil, fmt.Errorf("failed to parse RSA public key: %w", err)
199+
}
200+
rsaKey, ok := keyIface.(*rsa.PublicKey)
201+
if !ok {
202+
return nil, fmt.Errorf("expected RSA public key, got %T", keyIface)
203+
}
204+
return rsaKey, nil
173205
}
174-
return &rsaKey, nil
206+
return key, nil
175207
case "ecdsa":
176-
var ecKey ecdsa.PublicKey
177-
if err := jwk.Export(key, &ecKey); err != nil {
178-
return nil, err
208+
keyIface, err := x509.ParsePKIXPublicKey(block.Bytes)
209+
if err != nil {
210+
return nil, fmt.Errorf("failed to parse ECDSA public key: %w", err)
179211
}
180-
return &ecKey, nil
212+
ecKey, ok := keyIface.(*ecdsa.PublicKey)
213+
if !ok {
214+
return nil, fmt.Errorf("expected ECDSA public key, got %T", keyIface)
215+
}
216+
return ecKey, nil
181217
case "ed25519":
182-
var edKey ed25519.PublicKey
183-
if err := jwk.Export(key, &edKey); err != nil {
184-
return nil, err
218+
keyIface, err := x509.ParsePKIXPublicKey(block.Bytes)
219+
if err != nil {
220+
return nil, fmt.Errorf("failed to parse Ed25519 public key: %w", err)
221+
}
222+
edKey, ok := keyIface.(ed25519.PublicKey)
223+
if !ok {
224+
return nil, fmt.Errorf("expected Ed25519 public key, got %T", keyIface)
185225
}
186226
return edKey, nil
187227
default:

0 commit comments

Comments
 (0)