From ebc041ad9df5ce6cd3f3a5ad3174c860d8cb3d41 Mon Sep 17 00:00:00 2001 From: Fang-Pen Lin Date: Thu, 6 Nov 2025 20:28:55 -0800 Subject: [PATCH] Check url parsing error --- backend/bdd/features/pki/acme/auth.feature | 1 - .../bdd/features/pki/acme/dicrectory.feature | 14 ++-- backend/bdd/features/pki/acme/nonce.feature | 66 +++++++++---------- backend/bdd/features/pki/acme/order.feature | 28 ++++---- .../ee/services/pki-acme/pki-acme-service.ts | 12 +++- 5 files changed, 63 insertions(+), 58 deletions(-) diff --git a/backend/bdd/features/pki/acme/auth.feature b/backend/bdd/features/pki/acme/auth.feature index 4605e2eef..6de64dc30 100644 --- a/backend/bdd/features/pki/acme/auth.feature +++ b/backend/bdd/features/pki/acme/auth.feature @@ -3,7 +3,6 @@ Feature: Authorization Scenario: Get authorization Given I have an ACME cert profile as "acme_profile" When I have an ACME client connecting to {BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/directory -# # TODO: make it I have an account already instead? Then I register a new ACME account with email fangpen@infisical.com and EAB key id "{acme_profile.eab_kid}" with secret "{acme_profile.eab_secret}" as acme_account When I create certificate signing request as csr Then I add names to certificate signing request csr diff --git a/backend/bdd/features/pki/acme/dicrectory.feature b/backend/bdd/features/pki/acme/dicrectory.feature index dbb980ac3..1ba43871c 100644 --- a/backend/bdd/features/pki/acme/dicrectory.feature +++ b/backend/bdd/features/pki/acme/dicrectory.feature @@ -5,10 +5,10 @@ Feature: Directory When I send a "GET" request to "/api/v1/pki/acme/profiles/{acme_profile.id}/directory" Then the response status code should be "200" Then the response body should match JSON value - """ - { - "newNonce": "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/new-nonce", - "newAccount": "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/new-account", - "newOrder": "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/new-order" - } - """ + """ + { + "newNonce": "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/new-nonce", + "newAccount": "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/new-account", + "newOrder": "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/new-order" + } + """ diff --git a/backend/bdd/features/pki/acme/nonce.feature b/backend/bdd/features/pki/acme/nonce.feature index 673191e16..0116a89ed 100644 --- a/backend/bdd/features/pki/acme/nonce.feature +++ b/backend/bdd/features/pki/acme/nonce.feature @@ -23,17 +23,17 @@ Feature: Nonce Then I submit the certificate signing request PEM csr_pem certificate order to the ACME server as order Then I memorize with jq "" as When I send a raw ACME request to "" - """ - { - "protected": { - "alg": "RS256", - "nonce": "oFvnlFP1wIhRlYS2jTaXbA", - "url": "", - "kid": "{acme_account.uri}" - }, - "payload": {} - } - """ + """ + { + "protected": { + "alg": "RS256", + "nonce": "oFvnlFP1wIhRlYS2jTaXbA", + "url": "", + "kid": "{acme_account.uri}" + }, + "payload": {} + } + """ Then the value response.status_code should be equal to 400 Then the value response with jq ".status" should be equal to 400 Then the value response with jq ".type" should be equal to "urn:ietf:params:acme:error:badNonce" @@ -66,31 +66,31 @@ Feature: Nonce Then I submit the certificate signing request PEM csr_pem certificate order to the ACME server as order Then I peak and memorize the next nonce as nonce_value When I send a raw ACME request to "/api/v1/pki/acme/profiles/{acme_profile.id}/accounts/{account_id}/orders" - """ - { - "protected": { - "alg": "RS256", - "nonce": "{nonce_value}", - "url": "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/accounts/{account_id}/orders", - "kid": "{acme_account.uri}" - }, - "payload": {} - } - """ + """ + { + "protected": { + "alg": "RS256", + "nonce": "{nonce_value}", + "url": "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/accounts/{account_id}/orders", + "kid": "{acme_account.uri}" + }, + "payload": {} + } + """ Then the value response.status_code should be equal to 200 Then I memorize with jq "" as When I send a raw ACME request to "" - """ - { - "protected": { - "alg": "RS256", - "nonce": "{nonce_value}", - "url": "", - "kid": "{acme_account.uri}" - }, - "payload": {} - } - """ + """ + { + "protected": { + "alg": "RS256", + "nonce": "{nonce_value}", + "url": "", + "kid": "{acme_account.uri}" + }, + "payload": {} + } + """ Then the value response.status_code should be equal to 400 Then the value response with jq ".status" should be equal to 400 Then the value response with jq ".type" should be equal to "urn:ietf:params:acme:error:badNonce" diff --git a/backend/bdd/features/pki/acme/order.feature b/backend/bdd/features/pki/acme/order.feature index a4cf4f121..e2ea64e91 100644 --- a/backend/bdd/features/pki/acme/order.feature +++ b/backend/bdd/features/pki/acme/order.feature @@ -112,21 +112,21 @@ Feature: Order Then I register a new ACME account with email fangpen@infisical.com and EAB key id "{acme_profile.eab_kid}" with secret "{acme_profile.eab_secret}" as acme_account Then I peak and memorize the next nonce as nonce When I send a raw ACME request to "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/new-order" - """ - { - "protected": { - "alg": "RS256", - "nonce": "{nonce}", - "url": "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/new-order", - "kid": "{acme_account.uri}" - }, - "payload": { - "identifiers": [ - { "type": "dns", "value": "" } - ] + """ + { + "protected": { + "alg": "RS256", + "nonce": "{nonce}", + "url": "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/new-order", + "kid": "{acme_account.uri}" + }, + "payload": { + "identifiers": [ + { "type": "dns", "value": "" } + ] + } } - } - """ + """ Examples: Bad Identifier Vluaes | identifier_value | diff --git a/backend/src/ee/services/pki-acme/pki-acme-service.ts b/backend/src/ee/services/pki-acme/pki-acme-service.ts index 3f634d8e8..6e45f2a92 100644 --- a/backend/src/ee/services/pki-acme/pki-acme-service.ts +++ b/backend/src/ee/services/pki-acme/pki-acme-service.ts @@ -41,7 +41,6 @@ import { AcmeMalformedError, AcmeOrderNotReadyError, AcmeServerInternalError, - AcmeUnauthorizedError, AcmeUnsupportedIdentifierError } from "./pki-acme-errors"; import { buildUrl, extractAccountIdFromKid } from "./pki-acme-fns"; @@ -171,9 +170,16 @@ export const pkiAcmeServiceFactory = ({ const { protectedHeader: rawProtectedHeader, payload: rawPayload } = result; try { const protectedHeader = ProtectedHeaderSchema.parse(rawProtectedHeader); + const parsedUrl = (() => { + try { + return new URL(protectedHeader.url); + } catch (error) { + throw new AcmeMalformedError({ message: "Invalid URL in the protected header" }); + } + })(); // Validate the URL - if (new URL(protectedHeader.url).href !== url.href) { - throw new AcmeUnauthorizedError({ message: "URL mismatch in the protected header" }); + if (parsedUrl.href !== url.href) { + throw new AcmeMalformedError({ message: "URL mismatch in the protected header" }); } // Consume the nonce if (!protectedHeader.nonce) {