diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/base64.c | 62 | ||||
| -rw-r--r-- | common/base64.h | 6 | ||||
| -rw-r--r-- | common/pem.c | 54 | ||||
| -rw-r--r-- | common/pem.h | 5 | ||||
| -rw-r--r-- | common/tests/test-pem.c | 114 | 
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); | 
