Fix cert issues in Virtual Environments

This commit is contained in:
Reinier Criel 2025-11-26 15:48:29 -08:00
parent 9c55a95eb9
commit f5af26092a
3 changed files with 61 additions and 22 deletions

View file

@ -12,17 +12,6 @@ export function getCaCertPath() {
return path.join(certFolder, "ca-cert.pem");
}
/**
* @param {forge.pki.PublicKey} publicKey
* @returns {string}
*/
function createKeyIdentifier(publicKey) {
return forge.pki.getPublicKeyFingerprint(publicKey, {
encoding: "binary",
md: forge.md.sha1.create(),
});
}
/**
* @param {string} hostname
* @returns {{privateKey: string, certificate: string}}
@ -62,19 +51,39 @@ export function generateCertForHost(hostname) {
},
{
/*
extKeyUsage serverAuth is required for TLS server authentication.
This is especially important for Python venv environments, which use their own
certificate validation logic and will reject certificates lacking the serverAuth EKU.
Adding serverAuth does not impact other usages
Extended Key Usage (EKU) serverAuth extension
Needed for TLS server authentication. This extension indicates the certificate's
public key may be used for TLS WWW server authentication.
Python virtualenv environments (like pipx-installed Poetry) enforce this strictly
https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.12
*/
name: "extKeyUsage",
serverAuth: true,
},
{
/*
Subject Key Identifier (SKI)
Needed for Python virtualenv SSL validation and certificate chain building.
This extension provides a means of identifying certificates containing a particular public key.
Python virtualenv environments require this for proper certificate chain validation.
System Python installations may be more lenient.
https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.2
*/
name: "subjectKeyIdentifier",
subjectKeyIdentifier: createKeyIdentifier(cert.publicKey),
},
{
/*
Authority Key Identifier (AKI)
Needed for Python virtualenv SSL validation and certificate path validation.
This extension identifies the public key corresponding to the private key used to sign
this certificate. It links this certificate to its issuing CA certificate.
Without this, Python virtualenv certificate validation might fail
https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.1
*/
name: "authorityKeyIdentifier",
keyIdentifier: authorityKeyIdentifier,
},
@ -142,7 +151,7 @@ function generateCa() {
const attrs = [{ name: "commonName", value: "safe-chain proxy" }];
cert.setSubject(attrs);
cert.setIssuer(attrs);
cert.setIssuer(attrs); // Self-signed: issuer === subject
const keyIdentifier = createKeyIdentifier(cert.publicKey);
cert.setExtensions([
{
@ -156,10 +165,28 @@ function generateCa() {
digitalSignature: true,
keyEncipherment: true,
},
/*
Subject Key Identifier (SKI)
Needed for Python virtualenv SSL validation and certificate chain building.
This extension provides a means of identifying certificates containing a particular public key.
Python virtualenv environments require this for proper certificate chain validation.
System Python installations may be more lenient.
https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.2
*/
{
name: "subjectKeyIdentifier",
subjectKeyIdentifier: keyIdentifier,
},
/*
Authority Key Identifier (AKI)
Needed for Python virtualenv SSL validation and certificate path validation.
This extension identifies the public key corresponding to the private key used to sign
this certificate. It links this certificate to its issuing CA certificate.
Without this, Python virtualenv certificate validation might fail
https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.1
*/
{
name: "authorityKeyIdentifier",
keyIdentifier,
@ -172,3 +199,14 @@ function generateCa() {
certificate: cert,
};
}
/**
* @param {forge.pki.PublicKey} publicKey
* @returns {string}
*/
function createKeyIdentifier(publicKey) {
return forge.pki.getPublicKeyFingerprint(publicKey, {
encoding: "binary",
md: forge.md.sha1.create(),
});
}