mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-06-18 02:14:12 +02:00
Rework PEM parsing to not be order dependent
Some valid PEM file would not work because the private key was put before the certificate.
This commit is contained in:
parent
fb45baaf8c
commit
fdfb42b9f2
@ -209,15 +209,47 @@ g_tls_certificate_new_internal (const gchar *certificate_pem,
|
|||||||
#define PEM_PRIVKEY_HEADER "-----BEGIN RSA PRIVATE KEY-----"
|
#define PEM_PRIVKEY_HEADER "-----BEGIN RSA PRIVATE KEY-----"
|
||||||
#define PEM_PRIVKEY_FOOTER "-----END RSA PRIVATE KEY-----"
|
#define PEM_PRIVKEY_FOOTER "-----END RSA PRIVATE KEY-----"
|
||||||
|
|
||||||
static GTlsCertificate *
|
gchar *
|
||||||
|
parse_private_key (const gchar *data,
|
||||||
|
gsize data_len,
|
||||||
|
gboolean required,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
const gchar *start, *end;
|
||||||
|
|
||||||
|
start = g_strstr_len (data, data_len, PEM_PRIVKEY_HEADER);
|
||||||
|
if (!start)
|
||||||
|
{
|
||||||
|
if (required)
|
||||||
|
{
|
||||||
|
g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
|
||||||
|
_("No PEM-encoded private key found"));
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
end = g_strstr_len (start, data_len - (data - start), PEM_PRIVKEY_FOOTER);
|
||||||
|
if (!end)
|
||||||
|
{
|
||||||
|
g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
|
||||||
|
_("Could not parse PEM-encoded private key"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
end += strlen (PEM_PRIVKEY_FOOTER);
|
||||||
|
while (*end == '\r' || *end == '\n')
|
||||||
|
end++;
|
||||||
|
|
||||||
|
return g_strndup (start, end - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gchar *
|
||||||
parse_next_pem_certificate (const gchar **data,
|
parse_next_pem_certificate (const gchar **data,
|
||||||
const gchar *data_end,
|
const gchar *data_end,
|
||||||
gboolean required,
|
gboolean required,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
const gchar *start, *end, *next;
|
const gchar *start, *end;
|
||||||
gchar *cert_pem, *privkey_pem = NULL;
|
|
||||||
GTlsCertificate *cert;
|
|
||||||
|
|
||||||
start = g_strstr_len (*data, data_end - *data, PEM_CERTIFICATE_HEADER);
|
start = g_strstr_len (*data, data_end - *data, PEM_CERTIFICATE_HEADER);
|
||||||
if (!start)
|
if (!start)
|
||||||
@ -241,38 +273,9 @@ parse_next_pem_certificate (const gchar **data,
|
|||||||
while (*end == '\r' || *end == '\n')
|
while (*end == '\r' || *end == '\n')
|
||||||
end++;
|
end++;
|
||||||
|
|
||||||
cert_pem = g_strndup (start, end - start);
|
|
||||||
|
|
||||||
*data = end;
|
*data = end;
|
||||||
|
|
||||||
next = g_strstr_len (*data, data_end - *data, PEM_CERTIFICATE_HEADER);
|
return g_strndup (start, end - start);
|
||||||
start = g_strstr_len (*data, data_end - *data, PEM_PRIVKEY_HEADER);
|
|
||||||
if (start)
|
|
||||||
end = g_strstr_len (start, data_end - start, PEM_PRIVKEY_FOOTER);
|
|
||||||
|
|
||||||
if (start && (!next || start < next))
|
|
||||||
{
|
|
||||||
if (!end || (next && end > next))
|
|
||||||
{
|
|
||||||
g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
|
|
||||||
_("Could not parse PEM-encoded private key"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
end += strlen (PEM_PRIVKEY_FOOTER);
|
|
||||||
while (*end == '\r' || *end == '\n')
|
|
||||||
end++;
|
|
||||||
|
|
||||||
privkey_pem = g_strndup (start, end - start);
|
|
||||||
|
|
||||||
*data = end + strlen (PEM_PRIVKEY_FOOTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
cert = g_tls_certificate_new_internal (cert_pem, privkey_pem, error);
|
|
||||||
g_free (cert_pem);
|
|
||||||
g_free (privkey_pem);
|
|
||||||
|
|
||||||
return cert;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -298,14 +301,32 @@ g_tls_certificate_new_from_pem (const gchar *data,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
const gchar *data_end;
|
const gchar *data_end;
|
||||||
|
gchar *key_pem, *cert_pem;
|
||||||
|
GTlsCertificate *cert;
|
||||||
|
|
||||||
g_return_val_if_fail (data != NULL, NULL);
|
g_return_val_if_fail (data != NULL, NULL);
|
||||||
|
|
||||||
if (length == -1)
|
if (length == -1)
|
||||||
data_end = data + strlen (data);
|
length = strlen (data);
|
||||||
else
|
|
||||||
data_end = data + length;
|
data_end = data + length;
|
||||||
return parse_next_pem_certificate (&data, data_end, TRUE, error);
|
|
||||||
|
key_pem = parse_private_key (data, length, FALSE, error);
|
||||||
|
if (error && *error)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cert_pem = parse_next_pem_certificate (&data, data_end, TRUE, error);
|
||||||
|
if (error && *error)
|
||||||
|
{
|
||||||
|
g_free (key_pem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cert = g_tls_certificate_new_internal (cert_pem, key_pem, error);
|
||||||
|
g_free (key_pem);
|
||||||
|
g_free (cert_pem);
|
||||||
|
|
||||||
|
return cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -359,18 +380,34 @@ g_tls_certificate_new_from_files (const gchar *cert_file,
|
|||||||
{
|
{
|
||||||
GTlsCertificate *cert;
|
GTlsCertificate *cert;
|
||||||
gchar *cert_data, *key_data;
|
gchar *cert_data, *key_data;
|
||||||
|
gsize cert_len, key_len;
|
||||||
|
gchar *cert_pem, *key_pem;
|
||||||
|
const gchar *p;
|
||||||
|
|
||||||
if (!g_file_get_contents (cert_file, &cert_data, NULL, error))
|
if (!g_file_get_contents (cert_file, &cert_data, &cert_len, error))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!g_file_get_contents (key_file, &key_data, NULL, error))
|
p = cert_data;
|
||||||
|
cert_pem = parse_next_pem_certificate (&p, p + cert_len, TRUE, error);
|
||||||
|
g_free (cert_data);
|
||||||
|
if (error && *error)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!g_file_get_contents (key_file, &key_data, &key_len, error))
|
||||||
{
|
{
|
||||||
g_free (cert_data);
|
g_free (cert_pem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
key_pem = parse_private_key (key_data, key_len, TRUE, error);
|
||||||
|
g_free (key_data);
|
||||||
|
if (error && *error)
|
||||||
|
{
|
||||||
|
g_free (cert_pem);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cert = g_tls_certificate_new_internal (cert_data, key_data, error);
|
cert = g_tls_certificate_new_internal (cert_pem, key_pem, error);
|
||||||
g_free (cert_data);
|
g_free (cert_pem);
|
||||||
g_free (key_data);
|
g_free (key_pem);
|
||||||
return cert;
|
return cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,8 +432,7 @@ GList *
|
|||||||
g_tls_certificate_list_new_from_file (const gchar *file,
|
g_tls_certificate_list_new_from_file (const gchar *file,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
GTlsCertificate *cert;
|
GQueue queue = G_QUEUE_INIT;
|
||||||
GList *list, *l;
|
|
||||||
gchar *contents, *end;
|
gchar *contents, *end;
|
||||||
const gchar *p;
|
const gchar *p;
|
||||||
gsize length;
|
gsize length;
|
||||||
@ -404,25 +440,30 @@ g_tls_certificate_list_new_from_file (const gchar *file,
|
|||||||
if (!g_file_get_contents (file, &contents, &length, error))
|
if (!g_file_get_contents (file, &contents, &length, error))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
list = NULL;
|
|
||||||
end = contents + length;
|
end = contents + length;
|
||||||
p = contents;
|
p = contents;
|
||||||
while (p && *p)
|
while (p && *p)
|
||||||
{
|
{
|
||||||
cert = parse_next_pem_certificate (&p, end, FALSE, error);
|
gchar *cert_pem;
|
||||||
|
GTlsCertificate *cert = NULL;
|
||||||
|
|
||||||
|
cert_pem = parse_next_pem_certificate (&p, end, FALSE, error);
|
||||||
|
if (cert_pem)
|
||||||
|
{
|
||||||
|
cert = g_tls_certificate_new_internal (cert_pem, NULL, error);
|
||||||
|
g_free (cert_pem);
|
||||||
|
}
|
||||||
if (!cert)
|
if (!cert)
|
||||||
{
|
{
|
||||||
for (l = list; l; l = l->next)
|
g_list_free_full (queue.head, g_object_unref);
|
||||||
g_object_unref (l->data);
|
queue.head = NULL;
|
||||||
g_list_free (list);
|
|
||||||
list = NULL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
list = g_list_prepend (list, cert);
|
g_queue_push_tail (&queue, cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (contents);
|
g_free (contents);
|
||||||
return g_list_reverse (list);
|
return queue.head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user