You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@santuario.apache.org by bl...@apache.org on 2006/03/01 10:30:58 UTC

svn commit: r381962 - /xml/security/trunk/c/src/enc/XSECCryptoUtils.cpp

Author: blautenb
Date: Wed Mar  1 01:30:56 2006
New Revision: 381962

URL: http://svn.apache.org/viewcvs?rev=381962&view=rev
Log:
Partially implement SASLstringPrep for pass phrases as required for newer versions of XKMS spec

Modified:
    xml/security/trunk/c/src/enc/XSECCryptoUtils.cpp

Modified: xml/security/trunk/c/src/enc/XSECCryptoUtils.cpp
URL: http://svn.apache.org/viewcvs/xml/security/trunk/c/src/enc/XSECCryptoUtils.cpp?rev=381962&r1=381961&r2=381962&view=diff
==============================================================================
--- xml/security/trunk/c/src/enc/XSECCryptoUtils.cpp (original)
+++ xml/security/trunk/c/src/enc/XSECCryptoUtils.cpp Wed Mar  1 01:30:56 2006
@@ -30,9 +30,11 @@
 #include <xsec/enc/XSECCryptoUtils.hpp>
 #include <xsec/enc/XSECCryptoKeyHMAC.hpp>
 #include <xsec/utils/XSECPlatformUtils.hpp>
+#include <xsec/utils/XSECDOMUtils.hpp>
 
 #include <xercesc/util/Janitor.hpp>
 #include <xercesc/util/XMLString.hpp>
+#include <xercesc/util/XMLUniDefs.hpp>
 
 XERCES_CPP_NAMESPACE_USE
 
@@ -42,6 +44,7 @@
 
 int CleanXKMSPassPhrase(unsigned char * input, int inputLen, safeBuffer &output) {
 
+	// Now obsolete - use SASLCleanXKMSPassPhrase instead
 	int j = 0;
 	unsigned char c;
 	for (int i = 0; i < inputLen; ++i) {
@@ -61,6 +64,185 @@
 
 }
 
+int SASLCleanXKMSPassPhrase(unsigned char * input, int inputLen, safeBuffer &output) {
+
+	// For now - this does *not* implement the full SASLPrep algorithm.
+	// THe NFKC form is not trivial to implement - so this is kept very simple.
+	// TODO - Fix this - it can be an interoperability issue as pass phrases from
+	// different implementations could be treated differently.
+	// Currently we only check for prohibited unput for chars < 0xFFFF and drop any
+	// chars over 0xFFFF
+
+	XMLCh * uinput, *uoutput;
+	unsigned char * inp = new unsigned char[inputLen + 1];
+	ArrayJanitor<unsigned char> j_inp(inp);
+	memcpy(inp, input, inputLen);
+	inp[inputLen] = '\0';
+
+	uinput = XMLString::transcode((char *) inp);
+	unsigned int l = XMLString::stringLen(uinput);
+	uoutput = new XMLCh[l + 1];
+	ArrayJanitor<XMLCh> j_uinput(uinput);
+	ArrayJanitor<XMLCh> j_uoutput(uoutput);
+
+	unsigned int i, j;
+	j = 0;
+
+	XMLCh ch1;
+
+	for (i = 0; i < l; ++i) {
+		
+		ch1 = uinput[i];
+		// Case one - char is < 0x10000
+		if (ch1 < 0xD800 || ch1 > 0xDFFF) {
+
+			// OK - ch1 is "real" value - let's see if it is legal
+			// The following switch tables are derived from 
+			// RFC 3454 - see http://www.ietf.org/rfc/rfc3454.txt
+
+			// Non-ASCII Spaces - C.1.2
+			switch (ch1) {
+
+			case 0x00A0:		// NO-BREAK SPACE
+			case 0x1680:		// OGHAM SPACE MARK
+			case 0x2000:		// EN QUAD
+			case 0x2001:		// EM QUAD
+			case 0x2002:		// EN SPACE
+			case 0x2003:		// EM SPACE
+			case 0x2004:		// THREE-PER-EM SPACE
+			case 0x2005:		// FOUR-PER-EM SPACE
+			case 0x2006:		// SIX-PER-EM SPACE
+			case 0x2007:		// FIGURE SPACE
+			case 0x2008:		// PUNCTUATION SPACE
+			case 0x2009:		// THIN SPACE
+			case 0x200A:		// HAIR SPACE
+			case 0x200B:		// ZERO WIDTH SPACE
+			case 0x202F:		// NARROW NO-BREAK SPACE
+			case 0x205F:		// MEDIUM MATHEMATICAL SPACE
+			case 0x3000:		// IDEOGRAPHIC SPACE
+	
+				throw XSECException(XSECException::XKMSError,
+					"SASLCleanXKMSPassPhrase - Non ASCII space character in XKMS pass phrase");
+			default:
+
+				break;
+
+			}
+
+			// ASCII Control characters
+			if ((ch1 >=0 && ch1 <= 0x1F) || ch1 == 0x7F) {
+				throw XSECException(XSECException::XKMSError,
+					"SASLCleanXKMSPassPhrase - ASCII control character in XKMS pass phrase");
+			}
+
+			// Non-ASCII Control Characters
+			if ((ch1 >= 0x80 && ch1 <= 0x9F) || 
+				(ch1 >= 0x206A && ch1 <= 0x206F) ||
+				(ch1 >= 0xFFF9 && ch1 <= 0xFFFC)) {
+
+				throw XSECException(XSECException::XKMSError,
+					"SASLCleanXKMSPassPhrase - NON ASCII control character in XKMS pass phrase");
+			}
+
+			switch (ch1) {
+
+
+			case 0x06DD:		// ARABIC END OF AYAH
+			case 0x070F:		// SYRIAC ABBREVIATION MARK
+			case 0x180E:		// MONGOLIAN VOWEL SEPARATOR
+			case 0x200C:		// ZERO WIDTH NON-JOINER
+			case 0x200D:		// ZERO WIDTH JOINER
+			case 0x2028:		// LINE SEPARATOR
+			case 0x2029:		// PARAGRAPH SEPARATOR
+			case 0x2060:		// WORD JOINER
+			case 0x2061:		// FUNCTION APPLICATION
+			case 0x2062:		// INVISIBLE TIMES
+			case 0x2063:		// INVISIBLE SEPARATOR
+			case 0xFEFF:		// ZERO WIDTH NO-BREAK SPACE
+				throw XSECException(XSECException::XKMSError,
+					"SASLCleanXKMSPassPhrase - NON ASCII control character in XKMS pass phrase");
+			default:
+				break;			}
+		    // 1D173-1D17A; [MUSICAL CONTROL CHARACTERS] is not relevant as we are looking at
+		    // ch1 at the moment
+
+			// Private Use characters
+			if ((ch1 >= 0xE000 && ch1 <= 0xF8FF)) {
+
+				throw XSECException(XSECException::XKMSError,
+					"SASLCleanXKMSPassPhrase - Private Use character in XKMS pass phrase");
+			}
+
+			// Non-character code points
+			if ((ch1 >= 0xFDD0 && ch1 <= 0xFDEF) ||
+				(ch1 >= 0xFFFE && ch1 <= 0xFFFF)) {
+
+				throw XSECException(XSECException::XKMSError,
+					"SASLCleanXKMSPassPhrase - Non-character code points in XKMS pass phrase");
+			}
+
+			// Inappropriate for plain text characters
+   
+			switch (ch1) {
+			case 0xFFF9:		// INTERLINEAR ANNOTATION ANCHOR
+			case 0xFFFA:		// INTERLINEAR ANNOTATION SEPARATOR
+			case 0xFFFB:		// INTERLINEAR ANNOTATION TERMINATOR
+			case 0xFFFC:		// OBJECT REPLACEMENT CHARACTER
+			case 0xFFFD:		// REPLACEMENT CHARACTER
+				throw XSECException(XSECException::XKMSError,
+					"SASLCleanXKMSPassPhrase - Innappropriate for plain text chararcters in XKMS pass phrase");
+			default:
+				break;
+			}
+
+			// Inappripriate for canonical representation characters
+			if (ch1 >= 0x2FF0 && ch1 <= 0x2FFB) {
+				throw XSECException(XSECException::XKMSError,
+					"SASLCleanXKMSPassPhrase - Innappropriate for canonicalisation chararcters in XKMS pass phrase");
+			}
+
+			// Change display properties or are deprecated
+			switch (ch1) {
+			case 0x0340:		// COMBINING GRAVE TONE MARK
+			case 0x0341:		// COMBINING ACUTE TONE MARK
+			case 0x200E:		// LEFT-TO-RIGHT MARK
+			case 0x200F:		// RIGHT-TO-LEFT MARK
+			case 0x202A:		// LEFT-TO-RIGHT EMBEDDING
+			case 0x202B:		// RIGHT-TO-LEFT EMBEDDING
+			case 0x202C:		// POP DIRECTIONAL FORMATTING
+			case 0x202D:		// LEFT-TO-RIGHT OVERRIDE
+			case 0x202E:		// RIGHT-TO-LEFT OVERRIDE
+			case 0x206A:		// INHIBIT SYMMETRIC SWAPPING
+			case 0x206B:		// ACTIVATE SYMMETRIC SWAPPING
+			case 0x206C:		// INHIBIT ARABIC FORM SHAPING
+			case 0x206D:		// ACTIVATE ARABIC FORM SHAPING
+			case 0x206E:		// NATIONAL DIGIT SHAPES
+			case 0x206F:		// NOMINAL DIGIT SHAPES
+				throw XSECException(XSECException::XKMSError,
+					"SASLCleanXKMSPassPhrase - change display or deprecated chararcters in XKMS pass phrase");
+			default:
+				break;
+			}
+
+			// We got this far = just run with it for now
+			uoutput[j++] = ch1;
+		}
+		else {
+			throw XSECException(XSECException::XKMSError,
+				"SASLCleanXKMSPassPhrase - don't support XKMS pass phrase chars > 0xFFFF");
+		}
+	} /* for */
+	uoutput[j++] = chNull;
+
+	// Now transcode
+	char * utf8output= transcodeToUTF8(uoutput);
+	ArrayJanitor<char> j_utf8output(utf8output);
+	output.sbStrcpyIn(utf8output);
+
+	return strlen(utf8output);
+
+}
+
 int DSIG_EXPORT CalculateXKMSAuthenticationKey(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {
 
 	unsigned char keyVal[] = {XKMSAuthenticationValue};
@@ -135,21 +317,45 @@
 int DSIG_EXPORT CalculateXKMSKEK(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {
 
 	unsigned char keyVal[] = {XKMSKeyEncryption};
-
-	XSECCryptoKeyHMAC * k = XSECPlatformUtils::g_cryptoProvider->keyHMAC();
-	k->setKey(keyVal, 1);
-
-	XSECCryptoHash *h = XSECPlatformUtils::g_cryptoProvider->hashHMACSHA1();
-	Janitor<XSECCryptoHash> j_h(h);
-
-	h->setKey(k);
+	unsigned char shaOutput[22];	// SHA1 has 20 bytes of output
 
 	// Clean the input
 	safeBuffer sb;
-	int l = CleanXKMSPassPhrase(input, inputLen, sb);
+	int l = SASLCleanXKMSPassPhrase(input, inputLen, sb);
 
-	h->hash((unsigned char *) sb.rawBuffer(), l);
-	return h->finish(output, maxOutputLen);
+	// Need to iterate through until we have enough data
+	int bytesDone = 0, bytesToDo;;
+	shaOutput[0] = keyVal[0];
+	int keyLen = 1;
+	while (bytesDone < maxOutputLen) {
+		XSECCryptoKeyHMAC * k = XSECPlatformUtils::g_cryptoProvider->keyHMAC();
+		k->setKey(shaOutput, keyLen);
+
+		XSECCryptoHash *h = XSECPlatformUtils::g_cryptoProvider->hashHMACSHA1();
+		Janitor<XSECCryptoHash> j_h(h);
+
+		h->setKey(k);
+		delete(k);
+
+		// Now hash next round of data
+		h->hash((unsigned char *) sb.rawBuffer(), l);
+		keyLen = h->finish(shaOutput, 22);
+
+		// Copy into the output buffer
+		bytesToDo = maxOutputLen - bytesDone;
+		bytesToDo = bytesToDo > 20 ? 20 : bytesToDo;
+		memcpy(&output[bytesDone], shaOutput, bytesToDo);
+		bytesDone += bytesToDo;
+
+		// Set up for next key
+		shaOutput[0] ^= keyVal[0];
+		keyLen = 20;
+
+		j_h.release();
+		delete h;
+	}
+
+	return bytesDone;
 
 }