[gnome-keyring/dbus-api] [pkcs11] Factor out padding functionality, and add pkcs7 padding.



commit 28f2ff8044477d2e3fe9e5b7b0269217c47eb925
Author: Stef Walter <stef memberwebs com>
Date:   Wed Nov 18 21:14:40 2009 +0000

    [pkcs11] Factor out padding functionality, and add pkcs7 padding.
    
    Factor out the padding stuff into its own file gck-padding.[ch]
    and implement pkcs7 padding which we'll need shortly.

 pkcs11/gck/Makefile.am          |    1 +
 pkcs11/gck/gck-crypto.c         |   46 ++++---
 pkcs11/gck/gck-crypto.h         |    9 +-
 pkcs11/gck/gck-mechanism-rsa.c  |  175 +----------------------
 pkcs11/gck/gck-mechanism-rsa.h  |   33 +----
 pkcs11/gck/gck-padding.c        |  296 +++++++++++++++++++++++++++++++++++++++
 pkcs11/gck/gck-padding.h        |   86 +++++++++++
 pkcs11/gck/tests/Makefile.am    |    1 +
 pkcs11/gck/tests/test-padding.c |  182 ++++++++++++++++++++++++
 tests/gtest-helpers.h           |    5 +
 10 files changed, 608 insertions(+), 226 deletions(-)
---
diff --git a/pkcs11/gck/Makefile.am b/pkcs11/gck/Makefile.am
index fc9f983..9802eae 100644
--- a/pkcs11/gck/Makefile.am
+++ b/pkcs11/gck/Makefile.am
@@ -41,6 +41,7 @@ libgck_la_SOURCES = \
 	gck-memory-store.c gck-memory-store.h \
 	gck-module.c gck-module.h gck-module-ep.h \
 	gck-object.c gck-object.h \
+	gck-padding.c gck-padding.h \
 	gck-private-xsa-key.c gck-private-xsa-key.h \
 	gck-public-xsa-key.c gck-public-xsa-key.h \
 	gck-secret.c gck-secret.h \
diff --git a/pkcs11/gck/gck-crypto.c b/pkcs11/gck/gck-crypto.c
index db139fd..1d2a9c3 100644
--- a/pkcs11/gck/gck-crypto.c
+++ b/pkcs11/gck/gck-crypto.c
@@ -38,28 +38,32 @@
  */
 
 CK_RV
-gck_crypto_data_to_sexp (const gchar *format, guint nbits, GckCryptoPadding padding,
+gck_crypto_data_to_sexp (const gchar *format, guint nbits, GckPadding padding,
                          CK_BYTE_PTR data, CK_ULONG n_data, gcry_sexp_t *sexp)
 {
-	guchar *padded = NULL;
+	gpointer padded = NULL;
 	gcry_error_t gcry;
 	gcry_mpi_t mpi;
 	gsize n_padded;
+	gsize block;
 
 	g_assert (format);
 	g_assert (sexp);	
 	
 	g_return_val_if_fail (data, CKR_ARGUMENTS_BAD);
 
+	block = (nbits + 7) / 8;
+	if (n_data > block)
+		return CKR_DATA_LEN_RANGE;
+
 	if (padding) {
-		padded = (padding) (nbits, data, n_data, &n_padded);
-		if (!padded)
+		if (!(padding) (g_realloc, block, data, n_data, &padded, &n_padded))
 			return CKR_DATA_LEN_RANGE;
 	}
 		
 	/* Prepare the input s expression */
 	gcry = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, 
-                              padded ? padded : data, 
+	                      padded ? padded : data,
 	                      padded ? n_padded : n_data, NULL);
 	g_free (padded);
 
@@ -76,15 +80,17 @@ gck_crypto_data_to_sexp (const gchar *format, guint nbits, GckCryptoPadding padd
 
 CK_RV
 gck_crypto_sexp_to_data (gcry_sexp_t sexp, guint bits, CK_BYTE_PTR data,
-                         CK_ULONG *n_data, GckCryptoPadding padding, ...)
+                         CK_ULONG *n_data, GckPadding padding, ...)
 {
 	gcry_sexp_t at = NULL;
 	gsize n_block, offset, len;
 	gcry_mpi_t mpi = NULL;
+	gpointer padded;
 	guchar *block;
 	va_list va;
+	gboolean ret;
 	gcry_error_t gcry;
-	
+
 	g_assert (sexp);
 	g_assert (data);
 	g_assert (n_data);
@@ -102,7 +108,7 @@ gck_crypto_sexp_to_data (gcry_sexp_t sexp, guint bits, CK_BYTE_PTR data,
 	mpi = gcry_sexp_nth_mpi (at, 1, GCRYMPI_FMT_USG);
 	g_return_val_if_fail (at != NULL, CKR_GENERAL_ERROR);
 	gcry_sexp_release (at);
-	
+
 	/* Print out the MPI into the end of a temporary buffer */
 	n_block = (bits + 7) / 8;
 	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &len, mpi);
@@ -115,16 +121,16 @@ gck_crypto_sexp_to_data (gcry_sexp_t sexp, guint bits, CK_BYTE_PTR data,
 	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
 	g_return_val_if_fail (len == n_block - offset, CKR_GENERAL_ERROR);
 	gcry_mpi_release (mpi);
-		
+
 	/* Pad it properly if necessary */
 	if (padding != NULL) {
-		guchar *padded = (padding) (bits, block, n_block, &n_block);
+		ret = (padding) (g_realloc, n_block, block, n_block, &padded, &n_block);
 		g_free (block);
-		if (!padded)
+		if (ret == FALSE)
 			return CKR_DATA_LEN_RANGE;
 		block = padded;
 	}
-	
+
 	/* Now stuff it into the output buffer */
 	if (n_block > *n_data)
 		return CKR_BUFFER_TOO_SMALL;
@@ -132,7 +138,7 @@ gck_crypto_sexp_to_data (gcry_sexp_t sexp, guint bits, CK_BYTE_PTR data,
 	memcpy (data, block, n_block);
 	*n_data = n_block;
 	g_free (block);
-	
+
 	return CKR_OK;
 }
 
@@ -177,11 +183,11 @@ gck_crypto_encrypt_xsa (gcry_sexp_t sexp, CK_MECHANISM_TYPE mech, CK_BYTE_PTR da
 	switch (mech) {
 	case CKM_RSA_PKCS:
 		g_return_val_if_fail (algorithm == GCRY_PK_RSA, CKR_GENERAL_ERROR); 
-		rv = gck_mechanism_rsa_encrypt (sexp, gck_mechanism_rsa_pad_two, data, n_data, encrypted, n_encrypted);
+		rv = gck_mechanism_rsa_encrypt (sexp, gck_padding_pkcs1_pad_02, data, n_data, encrypted, n_encrypted);
 		break;
 	case CKM_RSA_X_509:
 		g_return_val_if_fail (algorithm == GCRY_PK_RSA, CKR_GENERAL_ERROR);
-		rv = gck_mechanism_rsa_encrypt (sexp, gck_mechanism_rsa_pad_raw, data, n_data, encrypted, n_encrypted);
+		rv = gck_mechanism_rsa_encrypt (sexp, gck_padding_zero_pad, data, n_data, encrypted, n_encrypted);
 		break;
 	default:
 		/* Again shouldn't be reached */
@@ -231,7 +237,7 @@ gck_crypto_decrypt_xsa (gcry_sexp_t sexp, CK_MECHANISM_TYPE mech, CK_BYTE_PTR en
 	switch (mech) {
 	case CKM_RSA_PKCS:
 		g_return_val_if_fail (algorithm == GCRY_PK_RSA, CKR_GENERAL_ERROR); 
-		rv = gck_mechanism_rsa_decrypt (sexp, gck_mechanism_rsa_unpad_two, encrypted, n_encrypted, data, n_data);
+		rv = gck_mechanism_rsa_decrypt (sexp, gck_padding_pkcs1_unpad_02, encrypted, n_encrypted, data, n_data);
 		break;
 	case CKM_RSA_X_509:
 		g_return_val_if_fail (algorithm == GCRY_PK_RSA, CKR_GENERAL_ERROR);
@@ -286,11 +292,11 @@ gck_crypto_sign_xsa (gcry_sexp_t sexp, CK_MECHANISM_TYPE mech, CK_BYTE_PTR data,
 	switch (mech) {
 	case CKM_RSA_PKCS:
 		g_return_val_if_fail (algorithm == GCRY_PK_RSA, CKR_GENERAL_ERROR); 
-		rv = gck_mechanism_rsa_sign (sexp, gck_mechanism_rsa_pad_one, data, n_data, signature, n_signature);
+		rv = gck_mechanism_rsa_sign (sexp, gck_padding_pkcs1_pad_01, data, n_data, signature, n_signature);
 		break;
 	case CKM_RSA_X_509:
 		g_return_val_if_fail (algorithm == GCRY_PK_RSA, CKR_GENERAL_ERROR);
-		rv = gck_mechanism_rsa_sign (sexp, gck_mechanism_rsa_pad_raw, data, n_data, signature, n_signature);
+		rv = gck_mechanism_rsa_sign (sexp, gck_padding_zero_pad, data, n_data, signature, n_signature);
 		break;
 	case CKM_DSA:
 		g_return_val_if_fail (algorithm == GCRY_PK_DSA, CKR_GENERAL_ERROR);
@@ -345,11 +351,11 @@ gck_crypto_verify_xsa (gcry_sexp_t sexp, CK_MECHANISM_TYPE mech, CK_BYTE_PTR dat
 	switch (mech) {
 	case CKM_RSA_PKCS:
 		g_return_val_if_fail (algorithm == GCRY_PK_RSA, CKR_GENERAL_ERROR); 
-		rv = gck_mechanism_rsa_verify (sexp, gck_mechanism_rsa_pad_one, data, n_data, signature, n_signature);
+		rv = gck_mechanism_rsa_verify (sexp, gck_padding_pkcs1_pad_01, data, n_data, signature, n_signature);
 		break;
 	case CKM_RSA_X_509:
 		g_return_val_if_fail (algorithm == GCRY_PK_RSA, CKR_GENERAL_ERROR);
-		rv = gck_mechanism_rsa_verify (sexp, gck_mechanism_rsa_pad_raw, data, n_data, signature, n_signature);
+		rv = gck_mechanism_rsa_verify (sexp, gck_padding_zero_pad, data, n_data, signature, n_signature);
 		break;
 	case CKM_DSA:
 		g_return_val_if_fail (algorithm == GCRY_PK_DSA, CKR_GENERAL_ERROR);
diff --git a/pkcs11/gck/gck-crypto.h b/pkcs11/gck/gck-crypto.h
index a32a95e..b4c40d3 100644
--- a/pkcs11/gck/gck-crypto.h
+++ b/pkcs11/gck/gck-crypto.h
@@ -22,6 +22,7 @@
 #ifndef GCKCRYPTO_H_
 #define GCKCRYPTO_H_
 
+#include "gck-padding.h"
 #include "gck-types.h"
 
 #include "pkcs11/pkcs11.h"
@@ -30,10 +31,6 @@
 
 #include <gcrypt.h>
 
-typedef guchar* (*GckCryptoPadding) (guint n_modulus, const guchar* raw, 
-                                     gsize n_raw, gsize *n_padded);
-
-
 void                     gck_crypto_initialize                         (void);
 
 CK_RV                    gck_crypto_prepare                            (GckSession *session,
@@ -112,12 +109,12 @@ CK_RV                    gck_crypto_sexp_to_data                       (gcry_sex
                                                                         guint bits,
                                                                         CK_BYTE_PTR data,
                                                                         CK_ULONG *n_data,
-                                                                        GckCryptoPadding padding,
+                                                                        GckPadding padding,
                                                                         ...) G_GNUC_NULL_TERMINATED;
 
 CK_RV                    gck_crypto_data_to_sexp                       (const gchar *format,
                                                                         guint nbits,
-                                                                        GckCryptoPadding padding,
+                                                                        GckPadding padding,
                                                                         CK_BYTE_PTR data,
                                                                         CK_ULONG n_data,
                                                                         gcry_sexp_t *sexp);
diff --git a/pkcs11/gck/gck-mechanism-rsa.c b/pkcs11/gck/gck-mechanism-rsa.c
index fea02f7..2d3a253 100644
--- a/pkcs11/gck/gck-mechanism-rsa.c
+++ b/pkcs11/gck/gck-mechanism-rsa.c
@@ -28,82 +28,11 @@
 #include "egg/egg-secure-memory.h"
 
 /* ----------------------------------------------------------------------------
- * INTERNAL
- */
-
-static void
-fill_random_nonzero (guchar *data, gsize n_data)
-{
-	guchar *rnd;
-	guint n_zero, i, j;
-
-	gcry_randomize (data, n_data, GCRY_STRONG_RANDOM);
-
-	/* Find any zeros in random data */
-	n_zero = 0;
-	for (i = 0; i < n_data; ++i) {
-		if (data[i] == 0x00)
-			++n_zero;
-	}
-
-	while (n_zero > 0) {
-		rnd = gcry_random_bytes (n_zero, GCRY_STRONG_RANDOM);
-		n_zero = 0;
-		for (i = 0, j = 0; i < n_data; ++i) {
-			if (data[i] != 0x00)
-				continue;
-
-			/* Use some of the replacement data */
-			data[i] = rnd[j];
-			++j;
-
-			/* It's zero again :( */
-			if (data[i] == 0x00)
-				n_zero++;
-		}
-
-		gcry_free (rnd);
-	}
-}
-
-static guchar*
-unpad_rsa_pkcs1 (guchar bt, guint n_modulus, const guchar* padded,
-                 gsize n_padded, gsize *n_raw)
-{
-	const guchar *at;
-	guint check;
-	guchar *raw;
-
-	check = (n_modulus + 7) / 8;
-
-	/* The absolute minimum size including padding */
-	g_return_val_if_fail (check >= 3 + 8, NULL);
-
-	if (n_padded != check)
-		return NULL;
-
-	/* Check the header */
-	if (padded[0] != 0x00 || padded[1] != bt)
-		return NULL;
-
-	/* The first zero byte after the header */
-	at = memchr (padded + 2, 0x00, n_padded - 2);
-	if (!at)
-		return NULL;
-
-	++at;
-	*n_raw = n_padded - (at - padded);
-	raw = g_new0 (guchar, *n_raw);
-	memcpy (raw, at, *n_raw);
-	return raw;
-}
-
-/* ----------------------------------------------------------------------------
  * PUBLIC
  */
 
 CK_RV
-gck_mechanism_rsa_encrypt (gcry_sexp_t sexp, GckCryptoPadding padding, CK_BYTE_PTR data,
+gck_mechanism_rsa_encrypt (gcry_sexp_t sexp, GckPadding padding, CK_BYTE_PTR data,
                            CK_ULONG n_data, CK_BYTE_PTR encrypted, CK_ULONG_PTR n_encrypted)
 {
 	gcry_sexp_t splain, sdata;
@@ -149,7 +78,7 @@ gck_mechanism_rsa_encrypt (gcry_sexp_t sexp, GckCryptoPadding padding, CK_BYTE_P
 }
 
 CK_RV
-gck_mechanism_rsa_decrypt (gcry_sexp_t sexp, GckCryptoPadding padding, CK_BYTE_PTR encrypted,
+gck_mechanism_rsa_decrypt (gcry_sexp_t sexp, GckPadding padding, CK_BYTE_PTR encrypted,
                            CK_ULONG n_encrypted, CK_BYTE_PTR data, CK_ULONG_PTR n_data)
 {
 	gcry_sexp_t splain, sdata;
@@ -197,7 +126,7 @@ gck_mechanism_rsa_decrypt (gcry_sexp_t sexp, GckCryptoPadding padding, CK_BYTE_P
 }
 
 CK_RV
-gck_mechanism_rsa_sign (gcry_sexp_t sexp, GckCryptoPadding padding, CK_BYTE_PTR data,
+gck_mechanism_rsa_sign (gcry_sexp_t sexp, GckPadding padding, CK_BYTE_PTR data,
                         CK_ULONG n_data, CK_BYTE_PTR signature, CK_ULONG_PTR n_signature)
 {
 	gcry_sexp_t ssig, sdata;
@@ -242,7 +171,7 @@ gck_mechanism_rsa_sign (gcry_sexp_t sexp, GckCryptoPadding padding, CK_BYTE_PTR
 }
 
 CK_RV
-gck_mechanism_rsa_verify (gcry_sexp_t sexp, GckCryptoPadding padding, CK_BYTE_PTR data,
+gck_mechanism_rsa_verify (gcry_sexp_t sexp, GckPadding padding, CK_BYTE_PTR data,
                           CK_ULONG n_data, CK_BYTE_PTR signature, CK_ULONG n_signature)
 {
 	gcry_sexp_t ssig, sdata;
@@ -289,99 +218,3 @@ gck_mechanism_rsa_verify (gcry_sexp_t sexp, GckCryptoPadding padding, CK_BYTE_PT
 
 	return CKR_OK;
 }
-
-/* ----------------------------------------------------------------------------
- * PADDING FUNCTIONS
- */
-
-
-guchar*
-gck_mechanism_rsa_pad_raw (guint n_modulus, const guchar* raw,
-                        gsize n_raw, gsize *n_padded)
-{
-	gint total, n_pad;
-	guchar *padded;
-
-	/*
-	 * 0x00 0x00 0x00 ... 0x?? 0x?? 0x?? ...
-	 *   padding               data
-	 */
-
-	total = (n_modulus + 7) / 8;
-	n_pad = total - n_raw;
-	if (n_pad < 0) /* minumum padding */
-		return NULL;
-
-	padded = g_new0 (guchar, total);
-	memset (padded, 0x00, n_pad);
-	memcpy (padded + n_pad, raw, n_raw);
-
-	*n_padded = total;
-	return padded;
-}
-
-guchar*
-gck_mechanism_rsa_pad_one (guint n_modulus, const guchar* raw,
-                           gsize n_raw, gsize *n_padded)
-{
-	gint total, n_pad;
-	guchar *padded;
-
-	/*
-	 * 0x00 0x01 0xFF 0xFF ... 0x00 0x?? 0x?? 0x?? ...
-	 *      type  padding              data
-	 */
-
-	total = (n_modulus + 7) / 8;
-	n_pad = total - 3 - n_raw;
-	if (n_pad < 8) /* minumum padding */
-		return NULL;
-
-	padded = g_new0 (guchar, total);
-	padded[1] = 1; /* Block type */
-	memset (padded + 2, 0xff, n_pad);
-	memcpy (padded + 3 + n_pad, raw, n_raw);
-
-	*n_padded = total;
-	return padded;
-}
-
-guchar*
-gck_mechanism_rsa_pad_two (guint n_modulus, const guchar* raw,
-                           gsize n_raw, gsize *n_padded)
-{
-	gint total, n_pad;
-	guchar *padded;
-
-	/*
-	 * 0x00 0x01 0x?? 0x?? ... 0x00 0x?? 0x?? 0x?? ...
-	 *      type  padding              data
-	 */
-
-	total = (n_modulus + 7) / 8;
-	n_pad = total - 3 - n_raw;
-	if (n_pad < 8) /* minumum padding */
-		return NULL;
-
-	padded = g_new0 (guchar, total);
-	padded[1] = 2; /* Block type */
-	fill_random_nonzero (padded + 2, n_pad);
-	memcpy (padded + 3 + n_pad, raw, n_raw);
-
-	*n_padded = total;
-	return padded;
-}
-
-guchar*
-gck_mechanism_rsa_unpad_one (guint bits, const guchar *padded,
-                             gsize n_padded, gsize *n_raw)
-{
-	return unpad_rsa_pkcs1 (0x01, bits, padded, n_padded, n_raw);
-}
-
-guchar*
-gck_mechanism_rsa_unpad_two (guint bits, const guchar *padded,
-                             gsize n_padded, gsize *n_raw)
-{
-	return unpad_rsa_pkcs1 (0x02, bits, padded, n_padded, n_raw);
-}
diff --git a/pkcs11/gck/gck-mechanism-rsa.h b/pkcs11/gck/gck-mechanism-rsa.h
index b263a57..fd8e7e0 100644
--- a/pkcs11/gck/gck-mechanism-rsa.h
+++ b/pkcs11/gck/gck-mechanism-rsa.h
@@ -37,56 +37,31 @@ static const CK_MECHANISM_TYPE GCK_CRYPTO_RSA_MECHANISMS[] = {
 };
 
 CK_RV                    gck_mechanism_rsa_encrypt                     (gcry_sexp_t sexp,
-                                                                        GckCryptoPadding padding,
+                                                                        GckPadding padding,
                                                                         CK_BYTE_PTR data,
                                                                         CK_ULONG n_data,
                                                                         CK_BYTE_PTR encrypted,
                                                                         CK_ULONG_PTR n_encrypted);
 
 CK_RV                    gck_mechanism_rsa_decrypt                     (gcry_sexp_t sexp,
-                                                                        GckCryptoPadding padding,
+                                                                        GckPadding padding,
                                                                         CK_BYTE_PTR encrypted,
                                                                         CK_ULONG n_encrypted,
                                                                         CK_BYTE_PTR data,
                                                                         CK_ULONG_PTR n_data);
 
 CK_RV                    gck_mechanism_rsa_sign                        (gcry_sexp_t sexp,
-                                                                        GckCryptoPadding padding,
+                                                                        GckPadding padding,
                                                                         CK_BYTE_PTR data,
                                                                         CK_ULONG n_data,
                                                                         CK_BYTE_PTR signature,
                                                                         CK_ULONG_PTR n_signature);
 
 CK_RV                    gck_mechanism_rsa_verify                      (gcry_sexp_t sexp,
-                                                                        GckCryptoPadding padding,
+                                                                        GckPadding padding,
                                                                         CK_BYTE_PTR data,
                                                                         CK_ULONG n_data,
                                                                         CK_BYTE_PTR signature,
                                                                         CK_ULONG n_signature);
 
-guchar*                  gck_mechanism_rsa_pad_raw                     (guint bits,
-                                                                        const guchar* raw,
-                                                                        gsize n_raw,
-                                                                        gsize *n_padded);
-
-guchar*                  gck_mechanism_rsa_pad_one                     (guint bits,
-                                                                        const guchar* raw,
-                                                                        gsize n_raw,
-                                                                        gsize *n_padded);
-
-guchar*                  gck_mechanism_rsa_pad_two                     (guint bits,
-                                                                        const guchar* raw,
-                                                                        gsize n_raw,
-                                                                        gsize *n_padded);
-
-guchar*                  gck_mechanism_rsa_unpad_one                   (guint bits,
-                                                                        const guchar *padded,
-                                                                        gsize n_padded,
-                                                                        gsize *n_raw);
-
-guchar*                  gck_mechanism_rsa_unpad_two                   (guint bits,
-                                                                        const guchar* padded,
-                                                                        gsize n_padded,
-                                                                        gsize *n_raw);
-
 #endif /* GCK_MECHANISM_RSA_H_ */
diff --git a/pkcs11/gck/gck-padding.c b/pkcs11/gck/gck-padding.c
new file mode 100644
index 0000000..094eda2
--- /dev/null
+++ b/pkcs11/gck/gck-padding.c
@@ -0,0 +1,296 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General  License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General  License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gck-padding.h"
+#include "gck-sexp.h"
+
+#include "egg/egg-libgcrypt.h"
+#include "egg/egg-secure-memory.h"
+
+/* ----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+fill_random_nonzero (guchar *data, gsize n_data)
+{
+	guchar *rnd;
+	guint n_zero, i, j;
+
+	gcry_randomize (data, n_data, GCRY_STRONG_RANDOM);
+
+	/* Find any zeros in random data */
+	n_zero = 0;
+	for (i = 0; i < n_data; ++i) {
+		if (data[i] == 0x00)
+			++n_zero;
+	}
+
+	while (n_zero > 0) {
+		rnd = gcry_random_bytes (n_zero, GCRY_STRONG_RANDOM);
+		n_zero = 0;
+		for (i = 0, j = 0; i < n_data; ++i) {
+			if (data[i] != 0x00)
+				continue;
+
+			/* Use some of the replacement data */
+			data[i] = rnd[j];
+			++j;
+
+			/* It's zero again :( */
+			if (data[i] == 0x00)
+				n_zero++;
+		}
+
+		gcry_free (rnd);
+	}
+}
+
+static gboolean
+unpad_pkcs1 (guchar bt, GckAllocator alloc, gsize block, const guchar* padded,
+             gsize n_padded, gpointer *raw, gsize *n_raw)
+{
+	const guchar *at;
+
+	if (block && n_padded % block != 0)
+		return FALSE;
+
+	/* Check the header */
+	if (padded[0] != 0x00 || padded[1] != bt)
+		return FALSE;
+
+	/* The first zero byte after the header */
+	at = memchr (padded + 2, 0x00, n_padded - 2);
+	if (!at)
+		return FALSE;
+
+	if (alloc == NULL)
+		alloc = g_realloc;
+
+	++at;
+	*n_raw = n_padded - (at - padded);
+	if (raw) {
+		*raw = (alloc) (NULL, MAX (*n_raw, 1));
+		if (*raw == NULL)
+			return FALSE;
+		memcpy (*raw, at, *n_raw);
+	}
+
+	return TRUE;
+}
+
+/* ----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+gboolean
+gck_padding_zero_pad (GckAllocator alloc, gsize block, gconstpointer raw,
+                      gsize n_raw, gpointer *padded, gsize *n_padded)
+{
+	guchar *pad;
+	gsize n_pad;
+
+	/*
+	 * 0x00 0x00 0x00 ... 0x?? 0x?? 0x?? ...
+	 *   padding               data
+	 */
+
+	g_return_val_if_fail (block != 0, FALSE);
+
+	*n_padded = ((n_raw + (block - 1)) / block) * block;
+	g_assert (n_raw <= *n_padded);
+	n_pad = *n_padded - n_raw;
+	g_assert (n_pad < block);
+
+	if (alloc == NULL)
+		alloc = g_realloc;
+
+	if (padded) {
+		*padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
+		if (pad == NULL)
+			return FALSE;
+		memset (pad, 0x00, n_pad);
+		memcpy (pad + n_pad, raw, n_raw);
+	}
+
+	return TRUE;
+}
+
+gboolean
+gck_padding_pkcs1_pad_01 (GckAllocator alloc, gsize block, gconstpointer raw,
+                           gsize n_raw, gpointer *padded, gsize *n_padded)
+{
+	guchar *pad;
+	gsize n_pad;
+
+	/*
+	 * 0x00 0x01 0xFF 0xFF ... 0x00 0x?? 0x?? 0x?? ...
+	 *      type  padding              data
+	 */
+
+	g_return_val_if_fail (block != 0, FALSE);
+	g_return_val_if_fail (block > 3, FALSE);
+
+	*n_padded = ((n_raw + 3 + (block - 1)) / block) * block;
+	g_assert (n_raw <= *n_padded);
+	n_pad = *n_padded - n_raw;
+	g_assert (n_pad <= block);
+	g_assert (n_pad >= 3);
+
+	if (alloc == NULL)
+		alloc = g_realloc;
+
+	if (padded) {
+		*padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
+		if (pad == NULL)
+			return FALSE;
+		pad[0] = 0; /* Prefix */
+		pad[1] = 1; /* Block type */
+		memset (pad + 2, 0xFF, n_pad - 3);
+		pad[n_pad - 1] = 0;
+		memcpy (pad + n_pad, raw, n_raw);
+	}
+
+	return TRUE;
+}
+
+gboolean
+gck_padding_pkcs1_pad_02 (GckAllocator alloc, gsize block, gconstpointer raw,
+                           gsize n_raw, gpointer *padded, gsize *n_padded)
+{
+	guchar *pad;
+	gsize n_pad;
+
+	/*
+	 * 0x00 0x01 0x?? 0x?? ... 0x00 0x?? 0x?? 0x?? ...
+	 *      type  padding              data
+	 */
+
+	g_return_val_if_fail (block != 0, FALSE);
+	g_return_val_if_fail (block > 3, FALSE);
+
+	*n_padded = ((n_raw + 3 + (block - 1)) / block) * block;
+	g_assert (n_raw <= *n_padded);
+	n_pad = *n_padded - n_raw;
+	g_assert (n_pad <= block);
+	g_assert (n_pad >= 3);
+
+	if (alloc == NULL)
+		alloc = g_realloc;
+
+	if (padded) {
+		*padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
+		if (pad == NULL)
+			return FALSE;
+		pad[0] = 0; /* Prefix */
+		pad[1] = 2; /* Block type */
+		fill_random_nonzero (pad + 2, n_pad - 3);
+		pad[n_pad - 1] = 0;
+		memcpy (pad + n_pad, raw, n_raw);
+	}
+
+	return TRUE;
+}
+
+gboolean
+gck_padding_pkcs1_unpad_01 (GckAllocator alloc, gsize block, gconstpointer padded,
+                             gsize n_padded, gpointer *raw, gsize *n_raw)
+{
+	return unpad_pkcs1 (0x01, alloc, block, padded, n_padded, raw, n_raw);
+}
+
+gboolean
+gck_padding_pkcs1_unpad_02 (GckAllocator alloc, gsize block, gconstpointer padded,
+                             gsize n_padded, gpointer *raw, gsize *n_raw)
+{
+	return unpad_pkcs1 (0x02, alloc, block, padded, n_padded, raw, n_raw);
+}
+
+gboolean
+gck_padding_pkcs7_pad (GckAllocator alloc, gsize block, gconstpointer raw,
+                       gsize n_raw, gpointer *padded, gsize *n_padded)
+{
+	guchar *pad;
+	gsize n_pad;
+
+	g_return_val_if_fail (block != 0, FALSE);
+	g_return_val_if_fail (block < 256, FALSE);
+
+	*n_padded = ((n_raw + block) / block) * block;
+	g_assert (n_raw < *n_padded);
+	n_pad = *n_padded - n_raw;
+	g_assert (n_pad > 0 && n_pad <= block);
+
+	if (alloc == NULL)
+		alloc = g_realloc;
+
+	if (padded) {
+		*padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
+		if (pad == NULL)
+			return FALSE;
+		memcpy (pad, raw, n_raw);
+		memset (pad + n_raw, n_pad, n_pad);
+	}
+
+	return TRUE;
+}
+
+gboolean
+gck_padding_pkcs7_unpad (GckAllocator alloc, gsize block, gconstpointer padded,
+                         gsize n_padded, gpointer *raw, gsize *n_raw)
+{
+	const guchar *pad;
+	gsize n_pad, i;
+
+	if (n_padded == 0)
+		return FALSE;
+
+	pad = padded;
+	n_pad = pad[n_padded - 1];
+
+	/* Validate the padding */
+	if (n_pad == 0 || n_pad > 256)
+		return FALSE;
+	if (n_pad > n_padded)
+		return FALSE;
+	if (block && n_pad > block)
+		return FALSE;
+	for (i = n_padded - n_pad; i < n_padded; ++i) {
+		if (pad[i] != n_pad)
+			return FALSE;
+	}
+
+	*n_raw = n_padded - n_pad;
+
+	if (alloc == NULL)
+		alloc = g_realloc;
+
+	if (raw) {
+		*raw = (alloc) (NULL, MAX (*n_raw, 1));
+		if (*raw == NULL)
+			return FALSE;
+		memcpy (*raw, pad, *n_raw);
+	}
+
+	return TRUE;
+}
diff --git a/pkcs11/gck/gck-padding.h b/pkcs11/gck/gck-padding.h
new file mode 100644
index 0000000..718e656
--- /dev/null
+++ b/pkcs11/gck/gck-padding.h
@@ -0,0 +1,86 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General  License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General  License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef GCK_PADDING_H_
+#define GCK_PADDING_H_
+
+#include <glib.h>
+
+typedef gpointer         (*GckAllocator)                               (gpointer,
+                                                                        gsize);
+
+typedef gboolean         (*GckPadding)                                 (GckAllocator alloc,
+                                                                        gsize n_block,
+                                                                        gconstpointer input,
+                                                                        gsize n_input,
+                                                                        gpointer *output,
+                                                                        gsize *n_output);
+
+gboolean                 gck_padding_zero_pad                          (GckAllocator alloc,
+                                                                        gsize n_block,
+                                                                        gconstpointer raw,
+                                                                        gsize n_raw,
+                                                                        gpointer *padded,
+                                                                        gsize *n_padded);
+
+gboolean                 gck_padding_pkcs1_pad_01                     (GckAllocator alloc,
+                                                                        gsize n_block,
+                                                                        gconstpointer raw,
+                                                                        gsize n_raw,
+                                                                        gpointer *padded,
+                                                                        gsize *n_padded);
+
+gboolean                 gck_padding_pkcs1_pad_02                     (GckAllocator alloc,
+                                                                        gsize n_block,
+                                                                        gconstpointer raw,
+                                                                        gsize n_raw,
+                                                                        gpointer *padded,
+                                                                        gsize *n_padded);
+
+gboolean                 gck_padding_pkcs1_unpad_01                   (GckAllocator alloc,
+                                                                        gsize n_block,
+                                                                        gconstpointer padded,
+                                                                        gsize n_padded,
+                                                                        gpointer *raw,
+                                                                        gsize *n_raw);
+
+gboolean                 gck_padding_pkcs1_unpad_02                   (GckAllocator alloc,
+                                                                        gsize n_block,
+                                                                        gconstpointer padded,
+                                                                        gsize n_padded,
+                                                                        gpointer *raw,
+                                                                        gsize *n_raw);
+
+gboolean                 gck_padding_pkcs7_pad                         (GckAllocator alloc,
+                                                                        gsize n_block,
+                                                                        gconstpointer raw,
+                                                                        gsize n_raw,
+                                                                        gpointer *padded,
+                                                                        gsize *n_padded);
+
+gboolean                 gck_padding_pkcs7_unpad                       (GckAllocator alloc,
+                                                                        gsize n_block,
+                                                                        gconstpointer raw,
+                                                                        gsize n_raw,
+                                                                        gpointer *padded,
+                                                                        gsize *n_padded);
+
+#endif /* GCK_PADDING_H_ */
diff --git a/pkcs11/gck/tests/Makefile.am b/pkcs11/gck/tests/Makefile.am
index 1a16b2b..a9cad0e 100644
--- a/pkcs11/gck/tests/Makefile.am
+++ b/pkcs11/gck/tests/Makefile.am
@@ -6,6 +6,7 @@ asn1-def-test.h: test.asn
 UNIT_AUTO = \
 	unit-test-attributes.c \
 	unit-test-sexp.c \
+	test-padding.c \
 	unit-test-data-asn1.c \
 	unit-test-data-der.c \
 	unit-test-object.c \
diff --git a/pkcs11/gck/tests/test-padding.c b/pkcs11/gck/tests/test-padding.c
new file mode 100644
index 0000000..1ab63c9
--- /dev/null
+++ b/pkcs11/gck/tests/test-padding.c
@@ -0,0 +1,182 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* test-padding.c: Test padding functionality
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "run-auto-test.h"
+
+#include "gck/gck-padding.h"
+
+#include <gcrypt.h>
+
+static void
+test_padding (GckPadding padding, gsize block, gconstpointer input,
+              gsize n_input, gconstpointer output, gsize n_output)
+{
+	gpointer result;
+	gsize n_result;
+
+	if (!(padding) (NULL, block, input, n_input, &result, &n_result)) {
+		g_assert (output == NULL);
+		return;
+	}
+
+	g_assert (result != NULL);
+	g_assert_cmpsize (n_output, ==, n_result);
+	g_assert (memcmp (output, result, n_output) == 0);
+	g_free (result);
+
+	/* Now make sure it can tell us the right length */
+	if (!(padding) (NULL, block, input, n_input, NULL, &n_result))
+		g_assert_not_reached ();
+
+	g_assert_cmpsize (n_output, ==, n_result);
+}
+
+DEFINE_TEST(zero_padding)
+{
+	guchar padded[] = { 0x00, 0x00, 0x00, 0x00, 'T', 'E', 'S', 'T' };
+	gchar raw[] = "TEST";
+	test_padding (gck_padding_zero_pad, 8, raw, 4, padded, 8);
+}
+
+DEFINE_TEST(zero_padding_no_data)
+{
+	guchar padded[] = { };
+	gchar raw[] = "";
+	test_padding (gck_padding_zero_pad, 8, raw, 0, padded, 0);
+}
+
+DEFINE_TEST(pkcs1_one_padding)
+{
+	guchar padded[] = { 0x00, 0x01, 0xFF, 0x00, 'T', 'E', 'S', 'T' };
+	gchar raw[] = "TEST";
+	test_padding (gck_padding_pkcs1_pad_01, 8, raw, 4, padded, 8);
+	test_padding (gck_padding_pkcs1_unpad_01, 8, padded, 8, raw, 4);
+}
+
+DEFINE_TEST(pkcs1_one_padding_no_data)
+{
+	guchar padded[] = { 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
+	gchar raw[] = "";
+	test_padding (gck_padding_pkcs1_pad_01, 8, raw, 0, padded, 8);
+	test_padding (gck_padding_pkcs1_unpad_01, 8, padded, 8, raw, 0);
+}
+
+DEFINE_TEST(pkcs1_two_padding)
+{
+	guchar padded[] = { 0x00, 0x02, 0x77, 0x66, 0x55, 0x00, 'T', 'E', };
+	gchar raw[] = "TE";
+	guchar *result;
+	gpointer vesult;
+	gsize n_result;
+
+	test_padding (gck_padding_pkcs1_unpad_02, 8, padded, 8, raw, 2);
+
+	/* PKCS#1 02 padding is unpredictable */
+	if (!gck_padding_pkcs1_pad_02 (NULL, 8, raw, 2, &vesult, &n_result))
+		g_assert_not_reached ();
+	result = vesult;
+	g_assert (result != NULL);
+	g_assert_cmpsize (n_result, ==, 8);
+	g_assert (result[0] == 0x00);
+	g_assert (result[1] == 0x02);
+	g_assert (result[2] != 0x00);
+	g_assert (result[3] != 0x00);
+	g_assert (result[4] != 0x00);
+	g_assert (result[5] == 0x00);
+	g_assert (result[6] == 'T');
+	g_assert (result[7] == 'E');
+}
+
+DEFINE_TEST(pkcs1_padding_invalid_prefix)
+{
+	guchar padded[] = { 0x01, 0x04, 0x04, 0x04 };
+	test_padding (gck_padding_pkcs1_unpad_01, 4, padded, 4, NULL, 0);
+}
+
+DEFINE_TEST(pkcs1_padding_invalid_type)
+{
+	guchar padded[] = { 0x00, 0x03, 0xFF, 0x00, 'T', 'E', 'S', 'T' };
+	test_padding (gck_padding_pkcs1_unpad_01, 8, padded, 8, NULL, 0);
+}
+
+DEFINE_TEST(pkcs1_padding_invalid_no_zero)
+{
+	guchar padded[] = { 0x00, 0x01, 0xFF, 0xFF, 'T', 'E', 'S', 'T' };
+	test_padding (gck_padding_pkcs1_unpad_01, 8, padded, 8, NULL, 0);
+}
+
+DEFINE_TEST(pkcs1_padding_invalid_length)
+{
+	guchar padded[] = { 0x00, 0x01, 0xFF, 0xFF, 'T', 'E', 'S' };
+	test_padding (gck_padding_pkcs1_unpad_01, 8, padded, 7, NULL, 0);
+}
+
+DEFINE_TEST(pkcs7_padding)
+{
+	guchar padded[] = { 'T', 'E', 'S', 'T', 0x04, 0x04, 0x04, 0x04 };
+	gchar raw[] = "TEST";
+
+	test_padding (gck_padding_pkcs7_pad, 8, raw, 4, padded, 8);
+	test_padding (gck_padding_pkcs7_unpad, 8, padded, 8, raw, 4);
+}
+
+DEFINE_TEST(pkcs7_padding_equal_block)
+{
+	guchar padded[] = { 'T', 'E', 'S', 'T', 'T', 'E', 'S', 'T', 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 };
+	gchar raw[] = "TESTTEST";
+
+	test_padding (gck_padding_pkcs7_pad, 8, raw, 8, padded, 16);
+	test_padding (gck_padding_pkcs7_unpad, 8, padded, 16, raw, 8);
+}
+
+DEFINE_TEST(pkcs7_padding_zero)
+{
+	guchar padded[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 };
+	gchar raw[] = "";
+
+	test_padding (gck_padding_pkcs7_pad, 8, raw, 0, padded, 8);
+	test_padding (gck_padding_pkcs7_unpad, 8, padded, 8, raw, 0);
+}
+
+DEFINE_TEST(pkcs7_padding_invalid_zero)
+{
+	guchar padded[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	test_padding (gck_padding_pkcs7_unpad, 8, padded, 8, NULL, 0);
+}
+
+DEFINE_TEST(pkcs7_padding_invalid_too_long)
+{
+	guchar padded[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 };
+	test_padding (gck_padding_pkcs7_unpad, 4, padded, 8, NULL, 0);
+	test_padding (gck_padding_pkcs7_unpad, 4, padded, 4, NULL, 0);
+}
+
+DEFINE_TEST(pkcs7_padding_invalid_different)
+{
+	guchar padded[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
+	test_padding (gck_padding_pkcs7_unpad, 8, padded, 8, NULL, 0);
+}
diff --git a/tests/gtest-helpers.h b/tests/gtest-helpers.h
index 82ec6e7..2716d5b 100644
--- a/tests/gtest-helpers.h
+++ b/tests/gtest-helpers.h
@@ -87,4 +87,9 @@ void test_external_fail (void);
 
 /* #define DEFINE_ABORT(x) void abort_x(void *__unused G_GNUC_UNUSED, gconstpointer __data G_GNUC_UNUSED)' */
 
+#ifndef g_assert_cmpsize
+#define g_assert_cmpsize(a, o, b) \
+	g_assert_cmpuint ((guint)(a), o, (guint)(b))
+#endif
+
 #endif /* GTEST_HELPERS_H_ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]