Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ v3.0.4 - YYYY-MM-DD
- 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!

`cupsCreateCredentialsRequest`, and `cupsSaveCredentials` being readable by
other users.
- Fixed the "m###" permissions suffix in `cupsFileOpen`.


v3.0.3 - 2026-08-20
Expand Down
2 changes: 1 addition & 1 deletion cups/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ cupsFileOpen(const char *filename, // I - Name of file
if ((ptr = strchr(mode, 'm')) != NULL && ptr[1] >= '0' && ptr[1] <= '7')
{
// Get permissions from mode string...
perm = (int)strtol(mode + 1, NULL, 8);
perm = (int)strtol(ptr + 1, NULL, 8);
}

// Open the file...
Expand Down
7 changes: 7 additions & 0 deletions cups/testcreds.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ do_unit_tests(void)
*chain; // Cert chain data
size_t chainlen; // Length of cert chain data
http_trust_t trust; // Trust in credentials
struct stat fileinfo; // Key file information
static const char * const alt_names[] =
{ // subjectAltName values
"printer.example.com",
Expand Down Expand Up @@ -442,6 +443,9 @@ do_unit_tests(void)
data = cupsCopyCredentialsKey(TEST_CERT_PATH, "_site_");
testEnd(data != NULL);
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);

}
else
{
Expand Down Expand Up @@ -520,6 +524,9 @@ do_unit_tests(void)
testEnd(data != NULL);
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.


testBegin("cupsCopyCredentialsRequest(altprinter w/alt names)");
data = cupsCopyCredentialsRequest(TEST_CERT_PATH, "altprinter");
testEnd(data != NULL);
Expand Down
4 changes: 2 additions & 2 deletions cups/tls-gnutls.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ cupsCreateCredentials(
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(err), 0);
goto done;
}
else if ((fp = cupsFileOpen(keyfile, "w")) != NULL)
else if ((fp = cupsFileOpen(keyfile, "wm600")) != NULL)
{
DEBUG_printf("1cupsCreateCredentials: Writing private key to \"%s\".", keyfile);
cupsFileWrite(fp, (char *)buffer, bytes);
Expand Down Expand Up @@ -586,7 +586,7 @@ cupsCreateCredentialsRequest(
DEBUG_printf("1cupsCreateCredentialsRequest: Unable to export private key: %s", gnutls_strerror(err));
goto done;
}
else if ((fp = cupsFileOpen(keyfile, "w")) != NULL)
else if ((fp = cupsFileOpen(keyfile, "wm600")) != NULL)
{
DEBUG_printf("1cupsCreateCredentialsRequest: Writing private key to \"%s\".", keyfile);
cupsFileWrite(fp, (char *)buffer, bytes);
Expand Down
26 changes: 24 additions & 2 deletions cups/tls-openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static X509_EXTENSION *openssl_create_san(const char *common_name, size_t num_al
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?

static bool openssl_validate_name(X509 *cert, const char *common_name);


Expand Down Expand Up @@ -370,7 +371,7 @@ cupsCreateCredentials(
http_make_path(keyfile, sizeof(keyfile), path, common_name, "key");
http_make_path(pubfile, sizeof(pubfile), path, common_name, "pub");

if ((bio = BIO_new_file(keyfile, "wb")) == NULL)
if ((bio = openssl_open_key(keyfile)) == NULL)
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
goto done;
Expand Down Expand Up @@ -606,7 +607,7 @@ cupsCreateCredentialsRequest(
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);

// Save them...
if ((bio = BIO_new_file(keyfile, "wb")) == NULL)
if ((bio = openssl_open_key(keyfile)) == NULL)
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
goto done;
Expand Down Expand Up @@ -2609,6 +2610,27 @@ openssl_load_x509(
}


//
// 'openssl_open_key()' - Create a private key file that only the owner can read.
//

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...

{
int fd; // File descriptor
BIO *bio; // Key file BIO


if ((fd = open(keyfile, O_CREAT | O_WRONLY | O_TRUNC, 0600)) < 0)
return (NULL);

if ((bio = BIO_new_fd(fd, BIO_CLOSE)) == NULL)
close(fd);

return (bio);
}


//
// 'openssl_validate_name()' - Check that the certificate is valid for the given name.
//
Expand Down
2 changes: 1 addition & 1 deletion cups/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ http_save_file(const char *path, // I - Directory path for certificate/key store
return (true);
}

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.

return (false);

if (write(fd, value, strlen(value)) < 0)
Expand Down
Loading