Implement more checks

This commit is contained in:
Fang-Pen Lin
2025-11-07 09:20:13 -08:00
parent ce3d70c30a
commit e7f098e63e
2 changed files with 25 additions and 7 deletions
@@ -324,26 +324,45 @@ export const pkiAcmeServiceFactory = ({
throw new AcmeExternalAccountRequiredError({ detail: "External account binding is required" }); throw new AcmeExternalAccountRequiredError({ detail: "External account binding is required" });
} }
const publicKeyThumbprint = await calculateJwkThumbprint(jwk, "sha256");
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({ const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
projectId: profile.projectId, projectId: profile.projectId,
projectDAL, projectDAL,
kmsService kmsService
}); });
const kmsDecryptor = await kmsService.decryptWithKmsKey({ const kmsDecryptor = await kmsService.decryptWithKmsKey({
kmsId: certificateManagerKmsId kmsId: certificateManagerKmsId
}); });
const eabSecret = await kmsDecryptor({ cipherTextBlob: profile.acmeConfig!.encryptedEabSecret }); const eabSecret = await kmsDecryptor({ cipherTextBlob: profile.acmeConfig!.encryptedEabSecret });
const encodedSecret = new TextEncoder().encode(eabSecret.toString());
try { try {
const { payload: eabPayload, protectedHeader: eabProtectedHeader } = await flattenedVerify( const { payload: eabPayload, protectedHeader: eabProtectedHeader } = await flattenedVerify(
externalAccountBinding, externalAccountBinding,
encodedSecret eabSecret
); );
const alg = eabProtectedHeader!.alg!; const eabAlg = eabProtectedHeader!.alg!;
if (!["HS256", "HS384", "HS512"].includes(alg)) { if (!["HS256", "HS384", "HS512"].includes(eabAlg)) {
throw new AcmeMalformedError({ detail: "Invalid algorithm for external account binding JWS payload" }); throw new AcmeMalformedError({ detail: "Invalid algorithm for external account binding JWS payload" });
} }
// Make sure the URL matches the expected URL
const url = eabProtectedHeader!.url!;
if (url !== buildUrl(profile.id, "/new-account")) {
throw new UnauthorizedError({ message: "External account binding URL mismatch" });
}
// Make sure the JWK in the EAB payload matches the one provided in the outer JWS payload
const decoder = new TextDecoder();
const decodedEabPayload = decoder.decode(eabPayload);
const eabPayloadJson = JSON.parse(decodedEabPayload);
const eabPayloadJwkThumbprint = await calculateJwkThumbprint(
eabPayloadJson.jwk as JsonWebKey,
alg as "sha256" | "sha384" | "sha512"
);
if (eabPayloadJwkThumbprint !== publicKeyThumbprint || eabAlg !== alg) {
throw new AcmeBadPublicKeyError({
message: "External account binding public key thumbprint or algorithm mismatch"
});
}
// Make sure the KID in the EAB payload matches the profile ID
if ((eabPayload as unknown as { kid: string }).kid !== profile.id) { if ((eabPayload as unknown as { kid: string }).kid !== profile.id) {
throw new UnauthorizedError({ message: "External account binding KID mismatch" }); throw new UnauthorizedError({ message: "External account binding KID mismatch" });
} }
@@ -358,7 +377,6 @@ export const pkiAcmeServiceFactory = ({
throw new AcmeServerInternalError({ detail: "Failed to verify EAB JWS payload" }); throw new AcmeServerInternalError({ detail: "Failed to verify EAB JWS payload" });
} }
const publicKeyThumbprint = await calculateJwkThumbprint(jwk, "sha256");
const existingAccount: TPkiAcmeAccounts | null = await acmeAccountDAL.findByProfileIdAndPublicKeyThumbprintAndAlg( const existingAccount: TPkiAcmeAccounts | null = await acmeAccountDAL.findByProfileIdAndPublicKeyThumbprintAndAlg(
profileId, profileId,
alg, alg,
@@ -832,7 +832,7 @@ export const certificateProfileServiceFactory = ({
kmsId: certificateManagerKmsId kmsId: certificateManagerKmsId
}); });
const eabSecret = await kmsDecryptor({ cipherTextBlob: profile.acmeConfig.encryptedEabSecret }); const eabSecret = await kmsDecryptor({ cipherTextBlob: profile.acmeConfig.encryptedEabSecret });
return { eabKid: profile.id, eabSecret: eabSecret.toString() }; return { eabKid: profile.id, eabSecret: eabSecret.toString("base64url") };
}; };
return { return {