summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2013-01-23 12:15:27 +0100
committerStef Walter <stefw@gnome.org>2013-02-05 15:00:25 +0100
commit5df24bf0fb8532e0ebdf5f2366834848fdf6097d (patch)
treeb858952507533e8708650fd61a128eb41aa6819d
parent722efb88cf12261d705e2a6dfb4aceab9ff7b76f (diff)
Implement code for writing PEM
* Based on the gcr code * Bring in base64 output code from BSD * Make sure to output base64 lines of 64 character length since this is what OpenSSL expects
-rw-r--r--common/base64.c62
-rw-r--r--common/base64.h6
-rw-r--r--common/pem.c54
-rw-r--r--common/pem.h5
-rw-r--r--common/tests/test-pem.c114
5 files changed, 237 insertions, 4 deletions
diff --git a/common/base64.c b/common/base64.c
index 7e66933..3f51c8d 100644
--- a/common/base64.c
+++ b/common/base64.c
@@ -190,3 +190,65 @@ p11_b64_pton (const char *src,
return (tarindex);
}
+
+int
+p11_b64_ntop (const unsigned char *src,
+ size_t srclength,
+ char *target,
+ size_t targsize,
+ int breakl)
+{
+ size_t len = 0;
+ unsigned char input[3];
+ unsigned char output[4];
+ size_t i;
+
+ while (srclength > 0) {
+ if (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+
+ } else if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ if (srclength == 1)
+ output[2] = 255;
+ else
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = 255;
+
+ srclength = 0;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (breakl && len % (breakl + 1) == 0) {
+ assert (len + 1 < targsize);
+ target[len++] = '\n';
+ }
+
+ assert(output[i] == 255 || output[i] < 64);
+ assert (len + 1 < targsize);
+
+ if (output[i] == 255)
+ target[len++] = Pad64;
+ else
+ target[len++] = Base64[output[i]];
+ }
+ }
+
+ assert (len < targsize);
+ target[len] = '\0'; /* Returned value doesn't count \0. */
+ return len;
+}
diff --git a/common/base64.h b/common/base64.h
index 4a2d1e7..cc27afd 100644
--- a/common/base64.h
+++ b/common/base64.h
@@ -50,4 +50,10 @@ int p11_b64_pton (const char *src,
unsigned char *target,
size_t targsize);
+int p11_b64_ntop (const unsigned char *src,
+ size_t srclength,
+ char *target,
+ size_t targsize,
+ int breakl);
+
#endif /* P11_BASE64_H_ */
diff --git a/common/pem.c b/common/pem.c
index 3d3d284..b3c6acd 100644
--- a/common/pem.c
+++ b/common/pem.c
@@ -36,6 +36,7 @@
#include "compat.h"
#include "base64.h"
+#include "buffer.h"
#include "debug.h"
#include "pem.h"
@@ -119,7 +120,7 @@ pem_find_end (const char *data,
data += n_type;
/* Next comes the suffix */
- if (ARMOR_SUFF_L > n_data && strncmp ((char *)data, ARMOR_SUFF, ARMOR_SUFF_L) != 0)
+ if (ARMOR_SUFF_L > n_data || strncmp ((char *)data, ARMOR_SUFF, ARMOR_SUFF_L) != 0)
return NULL;
/* The end of the data */
@@ -239,3 +240,54 @@ p11_pem_parse (const char *data,
return nfound;
}
+
+char *
+p11_pem_write (const unsigned char *contents,
+ size_t length,
+ const char *type,
+ size_t *pem_len)
+{
+ p11_buffer buffer;
+ size_t estimate;
+ size_t prefix;
+ char *target;
+ int len;
+
+ return_val_if_fail (contents || !length, NULL);
+ return_val_if_fail (type, NULL);
+ return_val_if_fail (pem_len, NULL);
+
+ /* Estimate from base64 data. Algorithm from Glib reference */
+ estimate = length * 4 / 3 + 7;
+ estimate += estimate / 64 + 1;
+
+ if (!p11_buffer_init_null (&buffer, estimate + 128))
+ return_val_if_reached (NULL);
+
+ p11_buffer_add (&buffer, ARMOR_PREF_BEGIN, ARMOR_PREF_BEGIN_L);
+ p11_buffer_add (&buffer, type, -1);
+ p11_buffer_add (&buffer, ARMOR_SUFF, ARMOR_SUFF_L);
+
+ prefix = buffer.len;
+ target = p11_buffer_append (&buffer, estimate);
+ return_val_if_fail (target != NULL, NULL);
+
+ /*
+ * OpenSSL is absolutely certain that it wants its PEM base64
+ * lines to be 64 characters in len.
+ */
+
+ len = p11_b64_ntop (contents, length, target, estimate, 64);
+
+ assert (len > 0);
+ assert (len <= estimate);
+ buffer.len = prefix + len;
+
+ p11_buffer_add (&buffer, "\n", 1);
+ p11_buffer_add (&buffer, ARMOR_PREF_END, ARMOR_PREF_END_L);
+ p11_buffer_add (&buffer, type, -1);
+ p11_buffer_add (&buffer, ARMOR_SUFF, ARMOR_SUFF_L);
+ p11_buffer_add (&buffer, "\n", 1);
+
+ return p11_buffer_steal (&buffer, pem_len);
+}
diff --git a/common/pem.h b/common/pem.h
index 1e88f1f..d84f418 100644
--- a/common/pem.h
+++ b/common/pem.h
@@ -47,4 +47,9 @@ unsigned int p11_pem_parse (const char *input,
p11_pem_sink sink,
void *user_data);
+char * p11_pem_write (const unsigned char *contents,
+ size_t length,
+ const char *type,
+ size_t *pem_len);
+
#endif /* P11_PEM_H_ */
diff --git a/common/tests/test-pem.c b/common/tests/test-pem.c
index 65a78d8..54a59d6 100644
--- a/common/tests/test-pem.c
+++ b/common/tests/test-pem.c
@@ -129,7 +129,7 @@ typedef struct {
int input_index;
int output_index;
int parsed;
-} SuccessClosure;
+} Closure;
static void
on_parse_pem_success (const char *type,
@@ -137,7 +137,7 @@ on_parse_pem_success (const char *type,
size_t length,
void *user_data)
{
- SuccessClosure *cl = user_data;
+ Closure *cl = user_data;
CuAssertIntEquals (cl->cu, success_fixtures[cl->input_index].output[cl->output_index].length, length);
CuAssertTrue (cl->cu, memcmp (success_fixtures[cl->input_index].output[cl->output_index].data, contents,
@@ -150,7 +150,7 @@ on_parse_pem_success (const char *type,
static void
test_pem_success (CuTest *cu)
{
- SuccessClosure cl;
+ Closure cl;
int ret;
int i;
int j;
@@ -232,6 +232,113 @@ test_pem_failure (CuTest *cu)
}
}
+typedef struct {
+ const char *input;
+ size_t length;
+ const char *type;
+ const char *output;
+} WriteFixture;
+
+typedef struct {
+ CuTest *cu;
+ WriteFixture *fixture;
+} WriteClosure;
+
+static WriteFixture write_fixtures[] = {
+ {
+ "\x69\x83\x4d\x5e\xab\x21\x95\x5c\x42\x76\x8f\x10\x7c\xa7\x97\x87"
+ "\x71\x94\xcd\xdf\xf2\x9f\x82\xd8\x21\x58\x10\xaf\x1e\x1a",
+ 30, "BLOCK1",
+ "-----BEGIN BLOCK1-----\n"
+ "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n"
+ "-----END BLOCK1-----\n",
+ },
+ {
+ "\x50\x31\x31\x2d\x4b\x49\x54\x0a\x0a\x50\x72\x6f\x76\x69\x64\x65"
+ "\x73\x20\x61\x20\x77\x61\x79\x20\x74\x6f\x20\x6c\x6f\x61\x64\x20"
+ "\x61\x6e\x64\x20\x65\x6e\x75\x6d\x65\x72\x61\x74\x65\x20\x50\x4b"
+ "\x43\x53\x23\x31\x31\x20\x6d\x6f\x64\x75\x6c\x65\x73\x2e\x20\x50"
+ "\x72\x6f\x76\x69\x64\x65\x73\x20\x61\x20\x73\x74\x61\x6e\x64\x61"
+ "\x72\x64\x0a\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x74\x69\x6f\x6e"
+ "\x20\x73\x65\x74\x75\x70\x20\x66\x6f\x72\x20\x69\x6e\x73\x74\x61"
+ "\x6c\x6c\x69\x6e\x67\x20\x50\x4b\x43\x53\x23\x31\x31\x20\x6d\x6f"
+ "\x64\x75\x6c\x65\x73\x20\x69\x6e\x20\x73\x75\x63\x68\x20\x61\x20"
+ "\x77\x61\x79\x20\x74\x68\x61\x74\x20\x74\x68\x65\x79\x27\x72\x65"
+ "\x0a\x64\x69\x73\x63\x6f\x76\x65\x72\x61\x62\x6c\x65\x2e\x0a\x0a"
+ "\x41\x6c\x73\x6f\x20\x73\x6f\x6c\x76\x65\x73\x20\x70\x72\x6f\x62"
+ "\x6c\x65\x6d\x73\x20\x77\x69\x74\x68\x20\x63\x6f\x6f\x72\x64\x69"
+ "\x6e\x61\x74\x69\x6e\x67\x20\x74\x68\x65\x20\x75\x73\x65\x20\x6f"
+ "\x66\x20\x50\x4b\x43\x53\x23\x31\x31\x20\x62\x79\x20\x64\x69\x66"
+ "\x66\x65\x72\x65\x6e\x74\x0a\x63\x6f\x6d\x70\x6f\x6e\x65\x6e\x74"
+ "\x73\x20\x6f\x72\x20\x6c\x69\x62\x72\x61\x72\x69\x65\x73\x20\x6c"
+ "\x69\x76\x69\x6e\x67\x20\x69\x6e\x20\x74\x68\x65\x20\x73\x61\x6d"
+ "\x65\x20\x70\x72\x6f\x63\x65\x73\x73\x2e\x0a",
+ 299, "LONG TYPE WITH SPACES",
+ "-----BEGIN LONG TYPE WITH SPACES-----\n"
+ "UDExLUtJVAoKUHJvdmlkZXMgYSB3YXkgdG8gbG9hZCBhbmQgZW51bWVyYXRlIFBL\n"
+ "Q1MjMTEgbW9kdWxlcy4gUHJvdmlkZXMgYSBzdGFuZGFyZApjb25maWd1cmF0aW9u\n"
+ "IHNldHVwIGZvciBpbnN0YWxsaW5nIFBLQ1MjMTEgbW9kdWxlcyBpbiBzdWNoIGEg\n"
+ "d2F5IHRoYXQgdGhleSdyZQpkaXNjb3ZlcmFibGUuCgpBbHNvIHNvbHZlcyBwcm9i\n"
+ "bGVtcyB3aXRoIGNvb3JkaW5hdGluZyB0aGUgdXNlIG9mIFBLQ1MjMTEgYnkgZGlm\n"
+ "ZmVyZW50CmNvbXBvbmVudHMgb3IgbGlicmFyaWVzIGxpdmluZyBpbiB0aGUgc2Ft\n"
+ "ZSBwcm9jZXNzLgo=\n"
+ "-----END LONG TYPE WITH SPACES-----\n"
+ },
+ {
+ "\x69\x83\x4d\x5e\xab\x21\x95\x5c\x42\x76\x8f\x10\x7c\xa7\x97\x87"
+ "\x71\x94\xcd\xdf\xf2\x9f\x82\xd8\x21\x58\x10\xaf",
+ 28, "BLOCK1",
+ "-----BEGIN BLOCK1-----\n"
+ "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrw==\n"
+ "-----END BLOCK1-----\n",
+ },
+ {
+ NULL,
+ }
+};
+
+static void
+on_parse_written (const char *type,
+ const unsigned char *contents,
+ size_t length,
+ void *user_data)
+{
+ WriteClosure *cl = user_data;
+
+ CuAssertStrEquals (cl->cu, cl->fixture->type, type);
+ CuAssertIntEquals (cl->cu, cl->fixture->length, length);
+ CuAssertTrue (cl->cu, memcmp (contents, cl->fixture->input, length) == 0);
+}
+
+static void
+test_pem_write (CuTest *cu)
+{
+ WriteFixture *fixture;
+ WriteClosure cl;
+ size_t length;
+ char *output;
+ unsigned int count;
+ int i;
+
+ for (i = 0; write_fixtures[i].input != NULL; i++) {
+ fixture = write_fixtures + i;
+
+ output = p11_pem_write ((unsigned char *)fixture->input,
+ fixture->length,
+ fixture->type, &length);
+ CuAssertStrEquals (cu, fixture->output, output);
+ CuAssertIntEquals (cu, strlen (fixture->output), length);
+
+ cl.fixture = fixture;
+ cl.cu = cu;
+
+ count = p11_pem_parse (output, length, on_parse_written, &cl);
+ CuAssertIntEquals (cu, 1, count);
+
+ free (output);
+ }
+}
+
int
main (void)
{
@@ -241,6 +348,7 @@ main (void)
SUITE_ADD_TEST (suite, test_pem_success);
SUITE_ADD_TEST (suite, test_pem_failure);
+ SUITE_ADD_TEST (suite, test_pem_write);
CuSuiteRun (suite);
CuSuiteSummary (suite, output);