Last active
September 27, 2020 11:54
-
-
Save svagionitis/2ca63d45fc16cbc92df8fb266bd0c017 to your computer and use it in GitHub Desktop.
Fix certificates in PEM format which don't have newlines
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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