Skip to content

Instantly share code, notes, and snippets.

@svagionitis
Last active September 27, 2020 11:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save svagionitis/2ca63d45fc16cbc92df8fb266bd0c017 to your computer and use it in GitHub Desktop.
Save svagionitis/2ca63d45fc16cbc92df8fb266bd0c017 to your computer and use it in GitHub Desktop.
Fix certificates in PEM format which don't have newlines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define PEM_CERTIFICATE_HEADER "-----BEGIN CERTIFICATE-----"
#define PEM_CERTIFICATE_FOOTER "-----END CERTIFICATE-----"
int
fix_pem (const char *filename)
{
int fd, fd_out;
int ret = 0;
char main_buf[72] = {0};
size_t output_buffer_sz = 0;
char *output_buffer = NULL, *tmp = NULL;
char filename_out[256];
ssize_t bytes_write;
fd = open (filename, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
fprintf (stderr, "*%s(): error opening file %s\n",
__func__, filename);
return -1;
}
/* Add header to the output buffer with new line */
output_buffer_sz += (strlen (PEM_CERTIFICATE_HEADER) + 1);
tmp = realloc (output_buffer, output_buffer_sz * sizeof (char));
if (tmp)
output_buffer = tmp;
else {
fprintf (stderr, "*%s(): error realloc\n", __func__);
ret = -1;
goto out;
}
memcpy (&output_buffer[output_buffer_sz - (strlen (PEM_CERTIFICATE_HEADER) + 1)],
PEM_CERTIFICATE_HEADER,
strlen (PEM_CERTIFICATE_HEADER));
output_buffer[output_buffer_sz - 1] = '\n';
/* Move the file descriptor after the header */
lseek (fd, strlen (PEM_CERTIFICATE_HEADER), SEEK_CUR);
/* Add the certificate to the output buffer with new line */
while (1) {
ssize_t bytes_read;
size_t idx;
char *start_footer;
bytes_read = read (fd, main_buf, sizeof (main_buf) - 1);
if (bytes_read < 0 && errno != EINTR) {
fprintf (stderr, "%s: Error reading file %s: %d\n",
__func__, filename, errno);
ret = -1;
goto out;
}
if (bytes_read == 0)
goto out;
/* Check if starting the footer */
start_footer = strchr (main_buf, '-');
if (start_footer) {
output_buffer_sz += ((start_footer - main_buf) + 1);
tmp = realloc (output_buffer, output_buffer_sz * sizeof (char));
if (tmp)
output_buffer = tmp;
else {
fprintf (stderr, "*%s(): error realloc\n", __func__);
ret = -1;
goto out;
}
idx = output_buffer_sz - ((start_footer - main_buf) +1);
memcpy (&output_buffer[idx], main_buf, (start_footer - main_buf));
output_buffer[output_buffer_sz - 1] = '\n';
break;
}
output_buffer_sz += (bytes_read + 1);
tmp = realloc (output_buffer, output_buffer_sz * sizeof (char));
if (tmp)
output_buffer = tmp;
else {
fprintf (stderr, "*%s(): error realloc\n", __func__);
ret = -1;
goto out;
}
idx = output_buffer_sz - (bytes_read + 1);
memcpy (&output_buffer[idx], main_buf, bytes_read);
output_buffer[output_buffer_sz - 1] = '\n';
}
output_buffer_sz += (strlen (PEM_CERTIFICATE_FOOTER) + 1);
tmp = realloc (output_buffer, output_buffer_sz * sizeof (char));
if (tmp)
output_buffer = tmp;
else {
fprintf (stderr, "*%s(): error realloc\n", __func__);
ret = -1;
goto out;
}
memcpy (&output_buffer[output_buffer_sz - (strlen (PEM_CERTIFICATE_FOOTER) + 1)],
PEM_CERTIFICATE_FOOTER,
strlen (PEM_CERTIFICATE_FOOTER));
output_buffer[output_buffer_sz - 1] = '\n';
fprintf (stdout, "*%s():\n%s", __func__, output_buffer);
/* Save the fixed version to a file */
sprintf (filename_out, "fix-%s", filename);
fd_out = open (filename_out, O_CREAT | O_WRONLY | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd < 0) {
fprintf (stderr, "*%s(): error opening file %s\n",
__func__, filename);
ret = -1;
goto out;
}
bytes_write = write (fd_out, output_buffer, output_buffer_sz);
if (bytes_write < 0 && errno != EINTR) {
fprintf (stderr, "%s: Error writing to file %s: %d\n",
__func__, filename_out, errno);
ret = -1;
goto out;
}
out:
if (output_buffer)
free (output_buffer);
close (fd);
close (fd_out);
return ret;
}
static int
fix_pem_certificate_buffer (const char *cert, char **fixed_cert)
{
const char pem_certificate_header[] = "-----BEGIN CERTIFICATE-----";
const char pem_certificate_footer[] = "-----END CERTIFICATE-----";
char *tmp = NULL;
size_t fixed_cert_sz = 0;
size_t pem_certificate_header_sz = strlen (pem_certificate_header);
size_t pem_certificate_footer_sz = strlen (pem_certificate_footer);
const char *payload = &cert[pem_certificate_header_sz];
if (!cert)
return -1;
if (cert[pem_certificate_header_sz + 1] == '\n') {
return 1;
}
/* Add header to the output buffer with new line */
fixed_cert_sz += pem_certificate_header_sz + 1;
tmp = realloc (*fixed_cert, fixed_cert_sz * sizeof (char));
if (tmp)
*fixed_cert = tmp;
else {
if (*fixed_cert)
free (*fixed_cert);
return -1;
}
memcpy (&(*fixed_cert)[fixed_cert_sz - (pem_certificate_header_sz + 1)],
pem_certificate_header,
pem_certificate_header_sz);
(*fixed_cert)[fixed_cert_sz - 1] = '\n';
/* Add the base64 encoded certificate to the output buffer with new line */
while (1) {
char payload_tmp_buffer[72];
size_t payload_tmp_buffer_sz = sizeof (payload_tmp_buffer);
size_t idx;
char *start_footer;
memcpy (payload_tmp_buffer, payload, payload_tmp_buffer_sz);
/* Check if starting the footer */
start_footer = strchr (payload_tmp_buffer, '-');
if (start_footer) {
fixed_cert_sz +=
(size_t) ((start_footer - payload_tmp_buffer) + 1);
tmp = realloc (*fixed_cert, fixed_cert_sz * sizeof (char));
if (tmp)
*fixed_cert = tmp;
else {
if (*fixed_cert)
free (*fixed_cert);
return -1;
}
idx = fixed_cert_sz
- (size_t) ((start_footer - payload_tmp_buffer) + 1);
memcpy (&(*fixed_cert)[idx],
payload_tmp_buffer,
(size_t) (start_footer - payload_tmp_buffer));
(*fixed_cert)[fixed_cert_sz - 1] = '\n';
break;
}
fixed_cert_sz += payload_tmp_buffer_sz + 1;
tmp = realloc (*fixed_cert, fixed_cert_sz * sizeof (char));
if (tmp)
*fixed_cert = tmp;
else {
if (*fixed_cert)
free (*fixed_cert);
return -1;
}
idx = fixed_cert_sz - (payload_tmp_buffer_sz + 1);
memcpy (&(*fixed_cert)[idx],
payload_tmp_buffer,
payload_tmp_buffer_sz);
(*fixed_cert)[fixed_cert_sz - 1] = '\n';
payload += payload_tmp_buffer_sz;
}
/* Add footer to the output buffer with new line */
fixed_cert_sz += pem_certificate_footer_sz + 1;
tmp = realloc (*fixed_cert, fixed_cert_sz * sizeof (char));
if (tmp)
*fixed_cert = tmp;
else {
if (*fixed_cert)
free (*fixed_cert);
return -1;
}
memcpy (&(*fixed_cert)[fixed_cert_sz - (pem_certificate_footer_sz + 1)],
pem_certificate_footer,
pem_certificate_footer_sz);
(*fixed_cert)[fixed_cert_sz - 1] = '\n';
return 0;
}
void
usage (char *argv0)
{
fprintf (stderr, "Usage: %s <filename>\n", argv0);
}
int main (int argc, char *argv[])
{
if (argc != 2) {
usage (argv[0]);
return -1;
}
fix_pem (argv[1]);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment