Documentation
¶
Overview ¶
Package crypto is the single cryptographic policy and primitives layer for the gmb-eudi EUDI modules. All JOSE/COSE/X.509 operations go through this package; no other module names an algorithm (ECCG Agreed Cryptographic Mechanisms v2.0, EW-PIO-01-003).
Import with an alias to avoid clashing with the standard library:
eudicrypto "github.com/gmb-eudi/go-eudi-crypto"
Index ¶
- Constants
- Variables
- func ECPublicKeyToJWK(pub stdcrypto.PublicKey) (map[string]any, error)
- func EncryptJWE(recipient stdcrypto.PublicKey, protected map[string]any, payload []byte) ([]byte, error)
- func GenerateEphemeralKey(crv string) (*ecdsa.PrivateKey, error)
- func JWKThumbprint(pub stdcrypto.PublicKey) (string, error)
- func ParseCertChain(raw []byte) ([]*x509.Certificate, error)
- func ParseECPublicKeyJWK(jwkJSON []byte) (stdcrypto.PublicKey, error)
- func SignCOSESign1(ctx context.Context, kp KeyProvider, keyID string, protected COSEHeader, ...) ([]byte, error)
- func SignJWS(ctx context.Context, kp KeyProvider, keyID string, protected map[string]any, ...) ([]byte, error)
- func VerifyChain(leaf *x509.Certificate, intermediates []*x509.Certificate, opts ChainOptions) ([][]*x509.Certificate, error)
- func X5CFromHeader(h Header) ([]*x509.Certificate, error)
- type COSEHeader
- type ChainOptions
- type Decrypter
- type Header
- type KeyProvider
- type Policy
- type StaticProvider
Constants ¶
const ECCGVersion = "2.0"
ECCGVersion is the pinned version of the ECCG Agreed Cryptographic Mechanisms document this policy table implements (EW-PIO-01-003).
Variables ¶
var ( ErrAlgorithmNotAllowed = errors.New("crypto: algorithm not allowed by ECCG policy") ErrCurveNotAllowed = errors.New("crypto: curve not allowed by ECCG policy") ErrKeyTypeNotAllowed = errors.New("crypto: key type not allowed by ECCG policy") ErrKeyNotFound = errors.New("crypto: key not found") ErrNoAnchors = errors.New("crypto: no trust anchors provided") ErrCritUnsupported = errors.New("crypto: unsupported critical header parameter") ErrAlgKeyMismatch = errors.New("crypto: token algorithm does not match key") ErrProtectedHeader = errors.New("crypto: forbidden protected header parameter") ErrMalformed = errors.New("crypto: malformed input") ErrVerificationFailed = errors.New("crypto: verification failed") ErrDecryptionFailed = errors.New("crypto: decryption failed") )
Sentinel errors. Callers map these to their own problem/reason codes; this library never carries HTTP semantics or framework dependencies.
Functions ¶
func ECPublicKeyToJWK ¶
ECPublicKeyToJWK serializes an EC public key to an [RFC 7518 §6.2] JWK as a map (ready to embed as an SD-JWT VC `cnf.jwk` object; RFC 7800). Rejects non-EC keys and curves not on the ECCG allow-list.
func EncryptJWE ¶
func EncryptJWE(recipient stdcrypto.PublicKey, protected map[string]any, payload []byte) ([]byte, error)
EncryptJWE encrypts payload to an EC recipient key using ECDH-ES key agreement with A256GCM content encryption (RFC 7516; ECCG Agreed Mechanisms / HAIP 1.0 encrypted-response profile). Compact serialization. The protected map may carry additional header params (e.g. OID4VP Annex B.2 apu = base64url(mdocGeneratedNonce)); alg/enc/epk are set by the library from policy and must not be supplied by the caller. The pair is never taken from the caller — algorithms are policy-driven, never chosen by callers or tokens.
func GenerateEphemeralKey ¶
func GenerateEphemeralKey(crv string) (*ecdsa.PrivateKey, error)
GenerateEphemeralKey creates a fresh EC keypair for per-session response encryption (HAIP response encryption; [OID4VP §8.3] direct_post.jwt). The curve must be ECCG-allowed.
func JWKThumbprint ¶ added in v0.0.2
JWKThumbprint computes the RFC 7638 JWK Thumbprint of an EC public key: the base64url-encoded (RawURLEncoding, no padding) SHA-256 digest of the UTF-8 JSON representation of the JWK's REQUIRED members only — for an EC key exactly {"kty","crv","x","y"} — serialized with no whitespace and member names in lexicographic order ([RFC 7638 §3, §3.1]). The hash is fixed to SHA-256 by RFC 7638 itself, not a caller-configurable ECCG policy choice.
Used to bind an ephemeral EC public key into an mdoc SessionTranscript (OpenID4VP 1.0 Annex B.2).
Delegates JWK construction to ECPublicKeyToJWK, which already returns exactly the four REQUIRED members for an EC key; this function does not reimplement JWK construction. Returns whatever error ECPublicKeyToJWK returns for a key that is not a supported EC public key (fail closed).
func ParseCertChain ¶
func ParseCertChain(raw []byte) ([]*x509.Certificate, error)
ParseCertChain parses one or more certificates from PEM (CERTIFICATE blocks) or raw DER. Untrusted input — fuzzed (FuzzParseCertChain).
func ParseECPublicKeyJWK ¶
ParseECPublicKeyJWK parses an RFC 7518 EC public-key JWK — as carried in an SD-JWT VC `cnf.jwk` (RFC 7800) — into a *ecdsa.PublicKey. Strict and fail-closed: only kty="EC" on an ECCG-allowed curve is accepted, x/y must be fixed-size big-endian coordinates, and the point is fully validated (on-curve, non-identity) by ecdsa.ParseUncompressedPublicKey. Malformed input is rejected and never panics (fuzzed: FuzzParseECPublicKeyJWK).
func SignCOSESign1 ¶
func SignCOSESign1(ctx context.Context, kp KeyProvider, keyID string, protected COSEHeader, payload []byte) ([]byte, error)
SignCOSESign1 signs payload as COSE_Sign1 ([RFC 9052 §4.2]). The alg label is derived from the key; callers must not set label 1 (algorithms are derived from keys, never chosen by callers or messages).
func SignJWS ¶
func SignJWS(ctx context.Context, kp KeyProvider, keyID string, protected map[string]any, payload []byte) ([]byte, error)
SignJWS signs payload as a compact JWS (RFC 7515). The alg header is derived from the key; callers must not set it (algorithms are derived from keys, never chosen by callers or tokens).
func VerifyChain ¶
func VerifyChain(leaf *x509.Certificate, intermediates []*x509.Certificate, opts ChainOptions) ([][]*x509.Certificate, error)
VerifyChain performs [RFC 5280 §6.1] path validation of leaf against the explicit anchor set. Fail closed: empty anchors is an error, never a system-pool fallback.
func X5CFromHeader ¶ added in v0.0.3
func X5CFromHeader(h Header) ([]*x509.Certificate, error)
X5CFromHeader decodes the [RFC 7515 §4.1.6] x5c header member (a JSON array of standard-base64-encoded DER certificates, leaf first) into parsed certificates. It is the symmetric decode counterpart of the certChain encode side and returns the certificates leaf-first, in header order. Returns (nil, nil) if the header carries no x5c member — absence is not an error; the caller decides whether a chain is required. The certificates are NOT validated against any trust anchor and their DER is NOT verified against any signature — this is a structural decode only; resolve/validate the chain through the trust layer before trusting it. Fail closed (ErrMalformed) if x5c is present but not an array, an entry is not a string, an entry is not valid standard base64, or a decoded entry is not a parseable certificate.
Types ¶
type COSEHeader ¶
COSEHeader carries integer-labeled COSE header parameters ([RFC 9052 §3]). EUDI profiles (ISO 18013-5 IssuerAuth/DeviceAuth) use integer labels only; string labels are not surfaced by this façade.
func VerifyCOSESign1 ¶
VerifyCOSESign1 verifies a COSE_Sign1 message ([RFC 9052 §4.2]) against an explicitly supplied key. The expected algorithm is derived from the key; a mismatching protected alg is rejected.
type ChainOptions ¶
type ChainOptions struct {
Anchors []*x509.Certificate
EKUs []x509.ExtKeyUsage // empty = any EKU accepted (callers pass profile EKUs)
At time.Time // required; explicitly injected clock, no hidden time.Now
}
ChainOptions configures VerifyChain. Anchors MUST come from go-eudi-trust — never the system pool, never inline PEM in services.
type Decrypter ¶
type Decrypter interface {
PrivateKey() stdcrypto.PrivateKey
}
Decrypter exposes the private key material needed for JWE ECDH-ES key agreement ([RFC 7518 §4.6]). In-memory implementations return the key directly; HSM-backed implementations require a native-decrypt extension of this interface — revisited when an HSM-backed provider lands.
type Header ¶
Header is a decoded JOSE protected header.
func DecryptJWE ¶
func DecryptJWE(ctx context.Context, kp KeyProvider, keyID string, token []byte) ([]byte, Header, error)
DecryptJWE decrypts a compact JWE (RFC 7516) addressed to keyID. The protected header's alg/enc pair is checked against the ECCG policy BEFORE any decryption is attempted (HAIP: ECDH-ES with AES-GCM only).
func ParseJWSHeader ¶ added in v0.0.3
ParseJWSHeader reads and JSON-decodes the protected header of a 3-segment compact JWS WITHOUT verifying the signature ([RFC 7515 §4.1]). Structural only — NEVER use its output to make a trust decision. It exists so a caller can inspect header members (e.g. an x5c chain, via X5CFromHeader) to resolve a candidate key BEFORE calling VerifyJWS; verify with VerifyJWS for anything security-relevant. Fail closed (ErrMalformed) on a wrong segment count, an empty segment, an undecodable base64url header, or a header that is not a JSON object. Must not panic on adversarial input (fuzzed: FuzzParseJWSHeader).
type KeyProvider ¶
type KeyProvider interface {
Signer(ctx context.Context, keyID string) (stdcrypto.Signer, error)
Decrypter(ctx context.Context, keyID string) (Decrypter, error)
Public(ctx context.Context, keyID string) (stdcrypto.PublicKey, error)
}
KeyProvider abstracts access to the operator's private keys. Planned implementations: filekeys (PEM/PKCS#8, dev), k8ssecret, pkcs11 (build tag), kms — only filekeys and the in-memory StaticProvider ship today.
type Policy ¶
type Policy interface {
AllowedJWSAlg(alg string) bool
AllowedJWEAlg(alg, enc string) bool
AllowedCOSEAlg(alg int64) bool
AllowedCurve(crv string) bool
HashForAlg(alg string) (stdcrypto.Hash, error)
AllowedHashName(name string) bool
HashForName(name string) (stdcrypto.Hash, error)
HashForMSODigestAlg(alg string) (stdcrypto.Hash, error)
}
Policy is the ECCG-pinned algorithm allow-list. Immutable; no env/config overrides for algorithms — they are derived from keys, never chosen by callers or tokens. Unknown = reject.
type StaticProvider ¶
type StaticProvider struct {
// contains filtered or unexported fields
}
StaticProvider is an in-memory KeyProvider for per-session ephemeral keys (GenerateEphemeralKey) and tests. The map is copied at construction and immutable afterwards, so concurrent use needs no locking.
func NewStaticProvider ¶
func NewStaticProvider(keys map[string]*ecdsa.PrivateKey) *StaticProvider
NewStaticProvider returns a StaticProvider serving the given keys. The map is copied, so callers may safely mutate their own copy afterwards.
func (*StaticProvider) Decrypter ¶
Decrypter returns a Decrypter wrapping the EC private key matching keyID.