Skip to content

create credential private key files with mode 0600 - #197

Open
tanjiroK-coder wants to merge 2 commits into
OpenPrinting:masterfrom
tanjiroK-coder:creds-private-key-mode
Open

tanjiroK-coder wants to merge 2 commits into
OpenPrinting:masterfrom
tanjiroK-coder:creds-private-key-mode

Conversation

@tanjiroK-coder

@tanjiroK-coder tanjiroK-coder commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

cupsCreateCredentials and cupsCreateCredentialsRequest write the new private key (.key or .ktm) with BIO_new_file(keyfile, "wb") in the OpenSSL backend and cupsFileOpen(keyfile, "w") in the GnuTLS backend, and cupsSaveCredentials writes it through http_save_file with mode 0644, so with the usual 022 umask every private key ends up 0644. The default ~/.cups/ssl store is created 0700, but any other directory passed as the path (ippeveprinter -K, or a server that calls cupsSetServerCredentials(path, cn, true) and lets _httpTLSStart auto-create its credentials) leaves the TLS server private key readable by every local user. I confirmed it with a small program that calls the three functions on a 0755 directory under umask 022: all three key files were 0644 before the change and are 0600 after. Key files are now created 0600 in both backends and in http_save_file, while certificates, public keys and CSRs keep their current modes. The GnuTLS side uses the documented "m###" suffix of cupsFileOpen, which never worked because the octal digits were parsed from mode + 1 instead of after the 'm' (so "wm600" created a mode 0000 file), and that one-character fix is included. testcreds now checks that site.key and altprinter.ktm are not group/other accessible; both checks fail on master and pass with the patch on macOS with OpenSSL (I could not build the GnuTLS backend locally).

Changelog:

  • Fixed private key files written by cupsCreateCredentials, cupsCreateCredentialsRequest, and cupsSaveCredentials being readable by other users.
  • Fixed the "m###" permissions suffix in cupsFileOpen.

@michaelrsweet michaelrsweet self-assigned this Oct 26, 2026
@michaelrsweet michaelrsweet added the bug Something isn't working label Oct 26, 2026
@michaelrsweet michaelrsweet added this to the Stable milestone Oct 26, 2026
@michaelrsweet

Copy link
Copy Markdown
Member

For future reference, please just put the changelog in the description. And it would be super helpful to have your commits GPG signed... :)

@michaelrsweet michaelrsweet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the general direction, see comments...

Comment thread cups/testcreds.c Outdated
free(data);

testBegin("_site_.key permissions");
testEnd(!stat(TEST_CERT_PATH "/_site_.key", &fileinfo) && !(fileinfo.st_mode & 077));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be useful to separate the mode check from the stat check, e.g.:

  • stat fails, testEndMessage(false, strerror(errno));
  • permission bad, testEndMessage(false, "wrong permissions, got %03o expected %03o.", fileinfo.st_mode & 0777, fileinfo.st_mode & 0700);
  • otherwise testEnd(true);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, split into the three cases with your messages: stat failure prints strerror, wrong mode prints got/expected, otherwise pass.

Comment thread cups/testcreds.c Outdated
free(data);

testBegin("altprinter.ktm permissions");
testEnd(!stat(TEST_CERT_PATH "/altprinter.ktm", &fileinfo) && !(fileinfo.st_mode & 077));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same test code as above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done here too.

Comment thread cups/tls-openssl.c Outdated
static time_t openssl_get_date(X509 *cert, int which);
//static void openssl_load_crl(void);
static STACK_OF(X509 *) openssl_load_x509(const char *credentials);
static BIO *openssl_open_key(const char *keyfile);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just add a permissions argument and make this openssl_open_file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to openssl_open_file with a mode argument. The other BIO_new_file(..., "wb") writes for the crt, pub and csr files go through it now with 0644, so every mode is explicit.

Comment thread cups/tls-openssl.c Outdated
//

static BIO * // O - Key file BIO or `NULL` on error
openssl_open_key(const char *keyfile) // I - Key filename

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think it would be good to have a mode argument so that the caller can choose the perms. I'm not sure what OpenSSL uses for the default...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the mode argument. BIO_new_file is just fopen, so the default was 0666 & ~umask, which is 0644 with the usual 022 umask. Callers now pass 0600 for the key and 0644 for everything else.

Comment thread cups/tls.c Outdated
}

if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, strcmp(ext, "key") ? 0644 : 0600)) < 0)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also needs to handle .ktm files.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, ktm is handled now.

Comment thread CHANGES.md Outdated
- Fixed a memory leak in `httpGetSecurity` when using GNU TLS.
- Fixed a memory leak in `cupsJWTImportString`.
- Fixed a bug in `cupsJWTExportString` with JSON output.
- Fixed private key files written by `cupsCreateCredentials`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted in my initial comment, please leave this change out of the PR. Thanks!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped, the entries are in the description now.

@tanjiroK-coder

Copy link
Copy Markdown
Contributor Author

Pushed the review changes and moved the changelog into the description. I have not got a GPG key set up yet, will sort that out for the next ones.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants