fix(control-plane): accept escaped-PEM client cert on /renew
nginx has no njs deployed, so the mTLS terminator forwards the verified client cert via $ssl_client_escaped_cert (URL-encoded PEM). headerPresentedCert now normalizes base64-DER, PEM, and escaped-PEM alike to raw DER. 281 tests pass.
This commit is contained in:
@@ -171,7 +171,15 @@ export function headerPresentedCert(headerName: string = DEFAULT_CLIENT_CERT_HEA
|
|||||||
const value = Array.isArray(raw) ? raw[0] : raw
|
const value = Array.isArray(raw) ? raw[0] : raw
|
||||||
if (typeof value !== 'string' || value.length === 0) return null
|
if (typeof value !== 'string' || value.length === 0) return null
|
||||||
try {
|
try {
|
||||||
return new Uint8Array(Buffer.from(value, 'base64'))
|
// The terminator may forward the verified cert as base64 DER, OR as PEM — including nginx's
|
||||||
|
// header-safe `$ssl_client_escaped_cert` (URL-encoded PEM). Normalize all three to raw DER:
|
||||||
|
// URL-decode if escaped, then strip PEM armor + whitespace to recover the base64 DER body.
|
||||||
|
let s = value.includes('%') ? safeDecodeUri(value) : value
|
||||||
|
if (s.includes('BEGIN CERTIFICATE')) {
|
||||||
|
s = s.replace(/-----[^-]+-----/g, '').replace(/\s+/g, '')
|
||||||
|
}
|
||||||
|
const der = Buffer.from(s, 'base64')
|
||||||
|
return der.length > 0 ? new Uint8Array(der) : null
|
||||||
} catch {
|
} catch {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -179,6 +187,15 @@ export function headerPresentedCert(headerName: string = DEFAULT_CLIENT_CERT_HEA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** URL-decode `value`, returning it unchanged if it is not valid percent-encoding. */
|
||||||
|
function safeDecodeUri(value: string): string {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(value)
|
||||||
|
} catch {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trust-anchor verification of the presented current cert (defense in depth: the mTLS terminator has
|
* Trust-anchor verification of the presented current cert (defense in depth: the mTLS terminator has
|
||||||
* already verified it, but this route must not trust a cert the terminator would never have accepted).
|
* already verified it, but this route must not trust a cert the terminator would never have accepted).
|
||||||
|
|||||||
Reference in New Issue
Block a user