@openeudi/openid4vp 0.9.3 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -16,7 +16,8 @@ interface AuthorizationRequest {
16
16
  state: string;
17
17
  }
18
18
  interface SignedAuthorizationRequestInput {
19
- hostname: string;
19
+ clientIdPrefix?: 'x509_san_dns' | 'x509_hash';
20
+ hostname?: string;
20
21
  requestUri: string;
21
22
  responseUri: string;
22
23
  nonce: string;
@@ -54,7 +55,10 @@ declare function createAuthorizationRequest(input: AuthorizationRequestInput, qu
54
55
  * carrying only `client_id` + `request_uri`, plus the JWS string the caller
55
56
  * must host at `requestUri` with Content-Type `application/oauth-authz-req+jwt`.
56
57
  *
57
- * Client Identifier Prefix is always `x509_san_dns` — other prefixes deferred.
58
+ * Client Identifier Prefix defaults to `x509_san_dns`; pass
59
+ * `clientIdPrefix: 'x509_hash'` to use the leaf certificate's SHA-256 hash
60
+ * instead (OpenID4VP 1.0 §5.9.3). `hostname` is required only for
61
+ * `x509_san_dns`.
58
62
  */
59
63
  declare function createSignedAuthorizationRequest(input: SignedAuthorizationRequestInput, query: DcqlQuery): Promise<SignedAuthorizationRequest>;
60
64
 
@@ -611,7 +615,7 @@ declare class LotlFetchError extends OpenID4VPError {
611
615
  declare class LotlSignatureError extends OpenID4VPError {
612
616
  readonly code: "lotl_signature_invalid";
613
617
  }
614
- type SignedRequestBuildErrorCode = 'empty_cert_chain' | 'hostname_cert_mismatch' | 'signing_key_cert_mismatch' | 'missing_encryption_jwk' | 'missing_encryption_alg' | 'missing_vp_formats' | 'unsupported_signing_alg' | 'empty_supported_enc_values';
618
+ type SignedRequestBuildErrorCode = 'empty_cert_chain' | 'hostname_cert_mismatch' | 'signing_key_cert_mismatch' | 'missing_encryption_jwk' | 'missing_encryption_alg' | 'missing_vp_formats' | 'unsupported_signing_alg' | 'empty_supported_enc_values' | 'missing_hostname';
615
619
  declare class SignedRequestBuildError extends OpenID4VPError {
616
620
  readonly code: SignedRequestBuildErrorCode;
617
621
  constructor(code: SignedRequestBuildErrorCode, message: string);
@@ -680,6 +684,6 @@ declare class LotlTrustStore implements TrustStore {
680
684
  private refresh;
681
685
  }
682
686
 
683
- declare const VERSION = "0.9.3";
687
+ declare const VERSION = "0.10.1";
684
688
 
685
689
  export { type AuthorizationRequest, type AuthorizationRequestInput, type AuthorizationResponse, type Cache, CertificateChainError, type ChainErrorReason, CompositeTrustStore, type CredentialClaims, type CredentialFormat, DecryptionFailedError, type EncryptedResponse, ExpiredCredentialError, type Fetcher, HAIP_DOCTYPE_NAMESPACES, type HaipQueryInput, type HaipValidationCode, HaipValidationError, type ICredentialParser, InMemoryCache, InvalidSignatureError, type IssuerInfo, type LotlAnchorMetadata, LotlFetchError, LotlSignatureError, LotlTrustStore, type LotlTrustStoreOptions, MalformedCredentialError, MdocParser, MissingDecryptionKeyError, MissingVerifierEncryptionKeyError, MultipleCredentialsNotSupportedError, NonceValidationError, OpenID4VPError, type ParseOptions, type PresentationResult, RevocationCheckFailedError, RevokedCertificateError, SdJwtParser, type SignedAuthorizationRequest, type SignedAuthorizationRequestInput, SignedRequestBuildError, type SignedRequestBuildErrorCode, StaticTrustStore, type TrustAnchor, TrustAnchorNotFoundError, type TrustStore, type TrustStoreHint, type TrustStoreInput, UnsupportedFormatError, UnsupportedJweError, VERSION, type VerifyAuthorizationResponseOptions, type VerifyOptions, type VerifyResult, buildHaipQuery, buildOid4vpSessionTranscript, buildOpenID4VPHandoverSessionTranscript, createAuthorizationRequest, createSignedAuthorizationRequest, decryptAuthorizationResponse, isHaipQuery, parsePresentation, validateHaipQuery, verifyAuthorizationResponse, verifyPresentation };
package/dist/index.d.ts CHANGED
@@ -16,7 +16,8 @@ interface AuthorizationRequest {
16
16
  state: string;
17
17
  }
18
18
  interface SignedAuthorizationRequestInput {
19
- hostname: string;
19
+ clientIdPrefix?: 'x509_san_dns' | 'x509_hash';
20
+ hostname?: string;
20
21
  requestUri: string;
21
22
  responseUri: string;
22
23
  nonce: string;
@@ -54,7 +55,10 @@ declare function createAuthorizationRequest(input: AuthorizationRequestInput, qu
54
55
  * carrying only `client_id` + `request_uri`, plus the JWS string the caller
55
56
  * must host at `requestUri` with Content-Type `application/oauth-authz-req+jwt`.
56
57
  *
57
- * Client Identifier Prefix is always `x509_san_dns` — other prefixes deferred.
58
+ * Client Identifier Prefix defaults to `x509_san_dns`; pass
59
+ * `clientIdPrefix: 'x509_hash'` to use the leaf certificate's SHA-256 hash
60
+ * instead (OpenID4VP 1.0 §5.9.3). `hostname` is required only for
61
+ * `x509_san_dns`.
58
62
  */
59
63
  declare function createSignedAuthorizationRequest(input: SignedAuthorizationRequestInput, query: DcqlQuery): Promise<SignedAuthorizationRequest>;
60
64
 
@@ -611,7 +615,7 @@ declare class LotlFetchError extends OpenID4VPError {
611
615
  declare class LotlSignatureError extends OpenID4VPError {
612
616
  readonly code: "lotl_signature_invalid";
613
617
  }
614
- type SignedRequestBuildErrorCode = 'empty_cert_chain' | 'hostname_cert_mismatch' | 'signing_key_cert_mismatch' | 'missing_encryption_jwk' | 'missing_encryption_alg' | 'missing_vp_formats' | 'unsupported_signing_alg' | 'empty_supported_enc_values';
618
+ type SignedRequestBuildErrorCode = 'empty_cert_chain' | 'hostname_cert_mismatch' | 'signing_key_cert_mismatch' | 'missing_encryption_jwk' | 'missing_encryption_alg' | 'missing_vp_formats' | 'unsupported_signing_alg' | 'empty_supported_enc_values' | 'missing_hostname';
615
619
  declare class SignedRequestBuildError extends OpenID4VPError {
616
620
  readonly code: SignedRequestBuildErrorCode;
617
621
  constructor(code: SignedRequestBuildErrorCode, message: string);
@@ -680,6 +684,6 @@ declare class LotlTrustStore implements TrustStore {
680
684
  private refresh;
681
685
  }
682
686
 
683
- declare const VERSION = "0.9.3";
687
+ declare const VERSION = "0.10.1";
684
688
 
685
689
  export { type AuthorizationRequest, type AuthorizationRequestInput, type AuthorizationResponse, type Cache, CertificateChainError, type ChainErrorReason, CompositeTrustStore, type CredentialClaims, type CredentialFormat, DecryptionFailedError, type EncryptedResponse, ExpiredCredentialError, type Fetcher, HAIP_DOCTYPE_NAMESPACES, type HaipQueryInput, type HaipValidationCode, HaipValidationError, type ICredentialParser, InMemoryCache, InvalidSignatureError, type IssuerInfo, type LotlAnchorMetadata, LotlFetchError, LotlSignatureError, LotlTrustStore, type LotlTrustStoreOptions, MalformedCredentialError, MdocParser, MissingDecryptionKeyError, MissingVerifierEncryptionKeyError, MultipleCredentialsNotSupportedError, NonceValidationError, OpenID4VPError, type ParseOptions, type PresentationResult, RevocationCheckFailedError, RevokedCertificateError, SdJwtParser, type SignedAuthorizationRequest, type SignedAuthorizationRequestInput, SignedRequestBuildError, type SignedRequestBuildErrorCode, StaticTrustStore, type TrustAnchor, TrustAnchorNotFoundError, type TrustStore, type TrustStoreHint, type TrustStoreInput, UnsupportedFormatError, UnsupportedJweError, VERSION, type VerifyAuthorizationResponseOptions, type VerifyOptions, type VerifyResult, buildHaipQuery, buildOid4vpSessionTranscript, buildOpenID4VPHandoverSessionTranscript, createAuthorizationRequest, createSignedAuthorizationRequest, decryptAuthorizationResponse, isHaipQuery, parsePresentation, validateHaipQuery, verifyAuthorizationResponse, verifyPresentation };
package/dist/index.js CHANGED
@@ -8247,14 +8247,23 @@ async function createSignedAuthorizationRequest(input, query) {
8247
8247
  "vpFormatsSupported is required and must be non-empty"
8248
8248
  );
8249
8249
  }
8250
+ const clientIdPrefix = input.clientIdPrefix ?? "x509_san_dns";
8250
8251
  const leafCert = new X509Certificate(toArrayBuffer(input.certificateChain[0]));
8251
- const sanDnsNames = extractDnsNames(leafCert);
8252
- if (!sanDnsNames.includes(input.hostname)) {
8252
+ if (clientIdPrefix === "x509_san_dns" && !input.hostname) {
8253
8253
  throw new SignedRequestBuildError(
8254
- "hostname_cert_mismatch",
8255
- `leaf cert SAN DNSName values [${sanDnsNames.join(", ")}] do not include hostname "${input.hostname}"`
8254
+ "missing_hostname",
8255
+ 'hostname is required for clientIdPrefix "x509_san_dns"'
8256
8256
  );
8257
8257
  }
8258
+ if (input.hostname) {
8259
+ const sanDnsNames = extractDnsNames(leafCert);
8260
+ if (!sanDnsNames.includes(input.hostname)) {
8261
+ throw new SignedRequestBuildError(
8262
+ "hostname_cert_mismatch",
8263
+ `leaf cert SAN DNSName values [${sanDnsNames.join(", ")}] do not include hostname "${input.hostname}"`
8264
+ );
8265
+ }
8266
+ }
8258
8267
  const signerPublicSpki = new Uint8Array(
8259
8268
  await crypto.subtle.exportKey("spki", input.signer.publicKey)
8260
8269
  );
@@ -8281,7 +8290,7 @@ async function createSignedAuthorizationRequest(input, query) {
8281
8290
  }
8282
8291
  }
8283
8292
  const state = input.state ?? v4();
8284
- const clientId = `x509_san_dns:${input.hostname}`;
8293
+ const clientId = clientIdPrefix === "x509_hash" ? `x509_hash:${await sha256Base64Url(input.certificateChain[0])}` : `x509_san_dns:${input.hostname}`;
8285
8294
  const now = Math.floor(Date.now() / 1e3);
8286
8295
  const clientMetadata = {
8287
8296
  vp_formats_supported: input.vpFormatsSupported
@@ -8298,8 +8307,6 @@ async function createSignedAuthorizationRequest(input, query) {
8298
8307
  clientMetadata.jwks = { keys: [jwk] };
8299
8308
  const encValues = enc3 ?? [...DEFAULT_SUPPORTED_ENC_VALUES];
8300
8309
  clientMetadata.encrypted_response_enc_values_supported = encValues;
8301
- clientMetadata.authorization_encrypted_response_alg = "ECDH-ES";
8302
- clientMetadata.authorization_encrypted_response_enc = encValues[0];
8303
8310
  }
8304
8311
  const payload = {
8305
8312
  iss: clientId,
@@ -8344,6 +8351,10 @@ function bytesEqual(a, b) {
8344
8351
  }
8345
8352
  return true;
8346
8353
  }
8354
+ async function sha256Base64Url(derCert) {
8355
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", toArrayBuffer(derCert)));
8356
+ return bytesToBase64(digest).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
8357
+ }
8347
8358
  function bytesToBase64(bytes) {
8348
8359
  let s = "";
8349
8360
  for (let i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i]);
@@ -9663,8 +9674,9 @@ async function verifyPresentation(vpToken, query, options) {
9663
9674
  const parsed = await parsePresentation(vpToken, options);
9664
9675
  const dcqlFormat = INTERNAL_TO_DCQL_FORMAT[parsed.format] ?? parsed.format;
9665
9676
  const decodedClaims = parsed.format === "mdoc" && parsed.namespacedClaims !== void 0 ? parsed.namespacedClaims : parsed.claims;
9677
+ const presentedCredentialQuery = query.credentials.find((c) => c.format === dcqlFormat) ?? query.credentials[0];
9666
9678
  const decoded = {
9667
- id: query.credentials[0]?.id ?? "presented",
9679
+ id: presentedCredentialQuery?.id ?? "presented",
9668
9680
  format: dcqlFormat,
9669
9681
  claims: decodedClaims
9670
9682
  };
@@ -9785,8 +9797,12 @@ async function verifyAuthorizationResponse(envelope, query, options) {
9785
9797
  if (queryIds.length > 1 || presentationCount > 1) {
9786
9798
  throw new MultipleCredentialsNotSupportedError(queryIds.length, presentationCount);
9787
9799
  }
9788
- const presentation = vpToken[queryIds[0]][0];
9789
- const decodedPresentation = query.credentials[0]?.format === "mso_mdoc" && typeof presentation === "string" ? base64UrlToBytes(presentation) : presentation;
9800
+ const presentedQueryId = queryIds[0];
9801
+ const presentation = vpToken[presentedQueryId][0];
9802
+ const presentedCredentialQuery = query.credentials.find(
9803
+ (c) => c.id === presentedQueryId
9804
+ );
9805
+ const decodedPresentation = presentedCredentialQuery?.format === "mso_mdoc" && typeof presentation === "string" ? base64UrlToBytes(presentation) : presentation;
9790
9806
  return verifyPresentation(decodedPresentation, query, options);
9791
9807
  }
9792
9808
 
@@ -10419,7 +10435,7 @@ function equalBytes(a, b) {
10419
10435
 
10420
10436
  // src/index.ts
10421
10437
  init_errors();
10422
- var VERSION = "0.9.3";
10438
+ var VERSION = "0.10.1";
10423
10439
  /*! Bundled license information:
10424
10440
 
10425
10441
  pvtsutils/build/index.es.js: