Skip to content

Read privateKey and decryptionPvk at construction, and refuse a key the option can't use #507

Open

Description

@cjbarth

privateKey and decryptionPvk are read the first time they are used. privateKey is read when a request, a logout message or metadata is signed, and decryptionPvk when an encrypted assertion or NameID arrives. A key that is malformed, or of a kind the option can't use, constructs without complaint and fails on the first request that needs it. For most such keys the error is OpenSSL's, and it doesn't name the option. With #447 merged, on Node 26:

Value Option Fails Error
an EC private key, PEM or Base64 decryptionPvk at the first encrypted message error:03000096:digital envelope routines::operation not supported for this keytype
a certificate or a public key, PEM decryptionPvk at the first encrypted message error:020000B3:rsa routines::missing private key
a certificate or a public key, PEM privateKey at the first signing, on both bindings error:1E08010C:DECODER routines::unsupported
Base64 that is no private key either at first use … is not a valid PEM or Base64 private key: Invalid PEM format.

In the next major, constructing a SAML with either option set to a value it can't use throws a TypeError naming the option, as a missing callbackUrl, issuer or idpCert already does.

Scope

  • initialize() reads privateKey and decryptionPvk the way they are read at use, through privateKeyToPem() and decryptionPvkToPem(). A value those refuse is refused at construction, with the same message.
  • Each must then hold a private key of a type the option can use. The type comes from Node's crypto.createPrivateKey().asymmetricKeyType. For decryptionPvk that is RSA, because xml-encryption unwraps the content key only with rsa-oaep-mgf1p or rsa-1_5. For privateKey it is RSA, because every signatureAlgorithm value is an RSA signature. Whether the data fits its PEM label stays with xml-crypto's toPem().
  • A PEM decryptionPvk is still handed to Node as given, so text around the message, such as Bag Attributes, stays accepted. The check at construction reads it the same way.
  • README.md: the privateKey and decryptionPvk sections say that the key is checked at construction, and which key types each option takes.

Why the next major

A configuration that holds an unusable key and never uses it works today, and would throw at startup. Examples are a decryptionPvk set although the IdP never encrypts, and a placeholder key in a test suite.

Decide first

  • Keep the check at use, or keep what construction read. SAML.options is public and can be changed after construction, so the check at use stays unless options becomes read-only. Keeping the PEM that construction produced would also stop every request from reading the key again.
  • idpCert, publicCert and decryptionCert. A plain value of each could be read at construction too. An idpCert callback can only be read when it runs, at verification.
  • rsa-pss keys. Node types an RSA-PSS key rsa-pss, not rsa. Decide whether privateKey may be one when signatureAlgorithm is sha256-mgf1.

Related: #422 requires signatureAlgorithm when signing, so the privateKey check can rely on it.

🤖 Generated with Claude Code

Activity

  1. added this to the v6 milestone on Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions