1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 /*
21  * XSEC
22  *
23  * XSECDOMUtils:= Utilities to manipulate DOM within XML-SECURITY
24  *
25  * $Id: XSECDOMUtils.cpp 1833341 2018-06-11 16:25:41Z scantor $
26  *
27  */
28 
29 // XSEC
30 
31 #include <xsec/framework/XSECError.hpp>
32 #include <xsec/xkms/XKMSConstants.hpp>
33 
34 #include "XSECDOMUtils.hpp"
35 
36 // Xerces
37 
38 #include <xercesc/util/XMLUniDefs.hpp>
39 #include <xercesc/util/Janitor.hpp>
40 #include <xercesc/util/PlatformUtils.hpp>
41 #include <xercesc/util/TransService.hpp>
42 
43 #include <string.h>
44 
45 XERCES_CPP_NAMESPACE_USE
46 
47 // --------------------------------------------------------------------------------
48 //           Utilities to manipulate DSIG namespaces
49 // --------------------------------------------------------------------------------
50 
getDSIGLocalName(const DOMNode * node)51 const XMLCh * getDSIGLocalName(const DOMNode *node) {
52 
53 	if (!strEquals(node->getNamespaceURI(), DSIGConstants::s_unicodeStrURIDSIG))
54 		return NULL; //DOMString("");
55 	else
56 		return node->getLocalName();
57 
58 }
59 
getDSIG11LocalName(const DOMNode * node)60 const XMLCh * getDSIG11LocalName(const DOMNode *node) {
61 
62 	if (!strEquals(node->getNamespaceURI(), DSIGConstants::s_unicodeStrURIDSIG11))
63 		return NULL; //DOMString("");
64 	else
65 		return node->getLocalName();
66 
67 }
68 
getECLocalName(const DOMNode * node)69 const XMLCh * getECLocalName(const DOMNode * node) {
70 
71 	// Exclusive Canonicalisation namespace
72 	// Probably should have a generic function
73 
74 	if (!strEquals(node->getNamespaceURI(), DSIGConstants::s_unicodeStrURIEC))
75 		return NULL;
76 	else
77 		return node->getLocalName();
78 
79 }
80 
getXPFLocalName(const DOMNode * node)81 const XMLCh * getXPFLocalName(const DOMNode * node) {
82 
83 	// XPath Filter namespace
84 
85 	if (!strEquals(node->getNamespaceURI(), DSIGConstants::s_unicodeStrURIXPF))
86 		return NULL;
87 	else
88 		return node->getLocalName();
89 
90 }
91 
getXENCLocalName(const DOMNode * node)92 const XMLCh * getXENCLocalName(const DOMNode *node) {
93 
94 	// XML Encryption namespace node
95 
96 	if (!strEquals(node->getNamespaceURI(), DSIGConstants::s_unicodeStrURIXENC))
97 		return NULL;
98 	else
99 		return node->getLocalName();
100 
101 }
102 
getXENC11LocalName(const DOMNode * node)103 const XMLCh * getXENC11LocalName(const DOMNode *node) {
104 
105 	// XML Encryption 1.1 namespace node
106 
107 	if (!strEquals(node->getNamespaceURI(), DSIGConstants::s_unicodeStrURIXENC11))
108 		return NULL;
109 	else
110 		return node->getLocalName();
111 
112 }
113 
114 #ifdef XSEC_XKMS_ENABLED
getXKMSLocalName(const DOMNode * node)115 const XMLCh * getXKMSLocalName(const DOMNode *node) {
116 
117 	// XKMS namespace node
118 
119 	if (!strEquals(node->getNamespaceURI(), XKMSConstants::s_unicodeStrURIXKMS))
120 		return NULL;
121 	else
122 		return node->getLocalName();
123 
124 }
125 #endif
126 
127 // --------------------------------------------------------------------------------
128 //           Find a nominated DSIG node in a document
129 // --------------------------------------------------------------------------------
130 
findDSIGNode(DOMNode * n,const char * nodeName)131 DOMNode *findDSIGNode(DOMNode *n, const char * nodeName) {
132 
133 	const XMLCh * name = getDSIGLocalName(n);
134 
135 	if (strEquals(name, nodeName)) {
136 
137 		return n;
138 
139 	}
140 
141 	DOMNode *child = n->getFirstChild();
142 
143 	while (child != NULL) {
144 
145 		DOMNode *ret = findDSIGNode(child, nodeName);
146 		if (ret != NULL)
147 			return ret;
148 		child = child->getNextSibling();
149 
150 	}
151 
152 	return child;
153 
154 }
155 
156 // --------------------------------------------------------------------------------
157 //           Find a nominated XENC node in a document
158 // --------------------------------------------------------------------------------
159 
findXENCNode(DOMNode * n,const char * nodeName)160 DOMNode *findXENCNode(DOMNode *n, const char * nodeName) {
161 
162 	const XMLCh * name = getXENCLocalName(n);
163 
164 	if (strEquals(name, nodeName)) {
165 
166 		return n;
167 
168 	}
169 
170 	DOMNode *child = n->getFirstChild();
171 
172 	while (child != NULL) {
173 
174 		DOMNode *ret = findXENCNode(child, nodeName);
175 		if (ret != NULL)
176 			return ret;
177 		child = child->getNextSibling();
178 
179 	}
180 
181 	return child;
182 
183 }
184 
185 // --------------------------------------------------------------------------------
186 //           Find particular type of node child
187 // --------------------------------------------------------------------------------
188 
findFirstChildOfType(DOMNode * n,DOMNode::NodeType t)189 DOMNode *findFirstChildOfType(DOMNode *n, DOMNode::NodeType t) {
190 
191 	DOMNode *c;
192 
193 	if (n == NULL)
194 		return n;
195 
196 	c = n->getFirstChild();
197 
198 	while (c != NULL && c->getNodeType() != t)
199 		c = c->getNextSibling();
200 
201 	return c;
202 
203 }
204 
findNextChildOfType(DOMNode * n,DOMNode::NodeType t)205 DOMNode * findNextChildOfType(DOMNode *n, DOMNode::NodeType t) {
206 
207 	DOMNode * s = n;
208 
209 	if (s == NULL)
210 		return s;
211 
212 	do {
213 		s = s->getNextSibling();
214 	} while (s != NULL && s->getNodeType() != t);
215 
216 	return s;
217 
218 }
219 
findFirstElementChild(DOMNode * n)220 DOMElement *findFirstElementChild(DOMNode *n) {
221 
222 	DOMNode *c;
223 
224 	if (n == NULL)
225 		return NULL;
226 
227 	c = n->getFirstChild();
228 
229 	while (c != NULL && c->getNodeType() != DOMNode::ELEMENT_NODE)
230 		c = c->getNextSibling();
231 
232 	return (DOMElement *) c;
233 
234 }
235 
findNextElementChild(DOMNode * n)236 DOMElement * findNextElementChild(DOMNode *n) {
237 
238 	DOMNode * s = n;
239 
240 	if (s == NULL)
241 		return NULL;
242 
243 	do {
244 		s = s->getNextSibling();
245 	} while (s != NULL && s->getNodeType() != DOMNode::ELEMENT_NODE);
246 
247 	return (DOMElement *) s;
248 
249 }
250 
251 // --------------------------------------------------------------------------------
252 //           Make a QName
253 // --------------------------------------------------------------------------------
254 
makeQName(safeBuffer & qname,safeBuffer & prefix,const char * localName)255 safeBuffer &makeQName(safeBuffer & qname, safeBuffer &prefix, const char * localName) {
256 
257 	if (prefix[0] == '\0') {
258 		qname = localName;
259 	}
260 	else {
261 		qname = prefix;
262 		qname.sbStrcatIn(":");
263 		qname.sbStrcatIn(localName);
264 	}
265 
266 	return qname;
267 
268 }
makeQName(safeBuffer & qname,const XMLCh * prefix,const char * localName)269 safeBuffer &makeQName(safeBuffer & qname, const XMLCh *prefix, const char * localName) {
270 
271 	if (prefix == NULL || prefix[0] == 0) {
272 		qname.sbTranscodeIn(localName);
273 	}
274 	else {
275 		qname.sbXMLChIn(prefix);
276 		qname.sbXMLChAppendCh(XERCES_CPP_NAMESPACE_QUALIFIER chColon);
277 		qname.sbXMLChCat(localName);	// Will transcode
278 	}
279 
280 	return qname;
281 }
282 
makeQName(safeBuffer & qname,const XMLCh * prefix,const XMLCh * localName)283 safeBuffer &makeQName(safeBuffer & qname, const XMLCh *prefix, const XMLCh * localName) {
284 
285 	if (prefix == NULL || prefix[0] == 0) {
286 		qname.sbXMLChIn(localName);
287 	}
288 	else {
289 		qname.sbXMLChIn(prefix);
290 		qname.sbXMLChAppendCh(XERCES_CPP_NAMESPACE_QUALIFIER chColon);
291 		qname.sbXMLChCat(localName);
292 	}
293 
294 	return qname;
295 }
296 
297 // --------------------------------------------------------------------------------
298 //           "Quick" Transcode (low performance)
299 // --------------------------------------------------------------------------------
300 
301 
302 
XMLT(const char * str)303 XMLT::XMLT(const char * str) {
304 
305 	mp_unicodeStr = XMLString::transcode(str);
306 
307 }
308 
~XMLT(void)309 XMLT::~XMLT (void) {
310 
311 	XSEC_RELEASE_XMLCH(mp_unicodeStr);
312 
313 }
314 
getUnicodeStr(void)315 XMLCh * XMLT::getUnicodeStr(void) {
316 
317 	return mp_unicodeStr;
318 
319 }
320 
321 // --------------------------------------------------------------------------------
322 //           Gather text from children
323 // --------------------------------------------------------------------------------
324 
gatherChildrenText(DOMNode * parent,safeBuffer & output)325 void gatherChildrenText(DOMNode * parent, safeBuffer &output) {
326 
327 	DOMNode * c = parent->getFirstChild();
328 
329 	output.sbXMLChIn(DSIGConstants::s_unicodeStrEmpty);
330 
331 	while (c != NULL) {
332 
333 		if (c->getNodeType() == DOMNode::TEXT_NODE)
334 			output.sbXMLChCat(c->getNodeValue());
335 
336 		c = c->getNextSibling();
337 
338 	}
339 
340 }
341 
342 // --------------------------------------------------------------------------------
343 //           Some UTF8 utilities
344 // --------------------------------------------------------------------------------
345 
transcodeFromUTF8(const unsigned char * src)346 XMLCh * transcodeFromUTF8(const unsigned char * src) {
347 
348 	// Take a UTF-8 buffer and transcode to UTF-16
349 
350 	safeBuffer fullDest;
351 	fullDest.sbXMLChIn(DSIGConstants::s_unicodeStrEmpty);
352 	XMLCh outputBuf[2050];
353 
354 	// Used to record byte sizes
355 	unsigned char charSizes[2050];
356 
357 	// Grab a transcoder
358 	XMLTransService::Codes failReason;
359 
360 	XMLTranscoder* t =
361 		XMLPlatformUtils::fgTransService->makeNewTranscoderFor("UTF-8",
362 					   failReason,
363 					   2*1024,
364 					   XMLPlatformUtils::fgMemoryManager);
365 	Janitor<XMLTranscoder> j_t(t);
366 
367 	// Need to loop through, 2K at a time
368 	XMLSize_t bytesEaten, bytesEatenCounter;
369 	XMLSize_t charactersEaten;
370 	XMLSize_t totalBytesEaten = 0;
371 	XMLSize_t bytesToEat = XMLString::stringLen((char *) src);
372 
373 	while (totalBytesEaten < bytesToEat) {
374 
375 	    XMLSize_t toEat = bytesToEat - totalBytesEaten;
376 
377 
378 		if (toEat > 2048)
379 			toEat = 2048;
380 
381 		t->transcodeFrom(&src[totalBytesEaten],
382 						toEat,
383 						outputBuf,
384 						2048,
385 						bytesEaten,
386 						charSizes);
387 
388 		// Determine how many characters were used
389 		bytesEatenCounter = 0;
390 		charactersEaten = 0;
391 		while (bytesEatenCounter < bytesEaten) {
392 			bytesEatenCounter += charSizes[charactersEaten++];
393 		}
394 
395 		outputBuf[charactersEaten] = chNull;
396 		fullDest.sbXMLChCat(outputBuf);
397 		totalBytesEaten += bytesEaten;
398 	}
399 
400 	// Dup and output
401 	return XMLString::replicate(fullDest.rawXMLChBuffer());
402 
403 }
404 
transcodeToUTF8(const XMLCh * src)405 char * transcodeToUTF8(const XMLCh * src) {
406 
407 	// Take a UTF-16 buffer and transcode to UTF-8
408 
409 	safeBuffer fullDest("");
410 	unsigned char outputBuf[2050];
411 
412 	// Grab a transcoder
413 	XMLTransService::Codes failReason;
414 
415 	XMLTranscoder* t =
416 		XMLPlatformUtils::fgTransService->makeNewTranscoderFor("UTF-8",
417 						   failReason,
418 						   2*1024,
419 						   XMLPlatformUtils::fgMemoryManager);
420 	Janitor<XMLTranscoder> j_t(t);
421 
422 	// Need to loop through, 2K at a time
423 	XMLSize_t charactersEaten, charactersOutput;
424 	XMLSize_t totalCharsEaten = 0;
425 	XMLSize_t charsToEat = XMLString::stringLen(src);
426 
427 	while (totalCharsEaten < charsToEat) {
428 
429 		XMLSize_t toEat = charsToEat - totalCharsEaten;
430 
431 		if (toEat > 2048)
432 			toEat = 2048;
433 
434 		charactersOutput = t->transcodeTo(&src[totalCharsEaten],
435 						toEat,
436 						(unsigned char * const) outputBuf,
437 						2048,
438 						charactersEaten,
439 						XMLTranscoder::UnRep_RepChar);
440 
441 		outputBuf[charactersOutput] = '\0';
442 		fullDest.sbStrcatIn((char *) outputBuf);
443 		totalCharsEaten += charactersEaten;
444 	}
445 
446 	// Dup and output
447 	return XMLString::replicate(fullDest.rawCharBuffer());
448 
449 }
450 
451 // --------------------------------------------------------------------------------
452 //           String decode/encode
453 // --------------------------------------------------------------------------------
454 
455 /*
456  * Distinguished names have a particular encoding that needs to be performed prior
457  * to enclusion in the DOM
458  */
459 
encodeDName(const XMLCh * toEncode)460 XMLCh * encodeDName(const XMLCh * toEncode) {
461 
462 	XERCES_CPP_NAMESPACE_USE;
463 
464 	safeBuffer result;
465 
466 	static XMLCh s_strEncodedSpace[] = {
467 		chBackSlash,
468 		chDigit_2,
469 		chDigit_0,
470 		chNull
471 	};
472 
473 	result.sbXMLChIn(DSIGConstants::s_unicodeStrEmpty);
474 
475 	if (toEncode == NULL) {
476 		return NULL;
477 	}
478 
479 
480 	// Find where the trailing whitespace starts
481 	const XMLCh * ws = &toEncode[XMLString::stringLen(toEncode)];
482 
483 	ws--;
484 	while (ws != toEncode &&
485 		(*ws == '\t' || *ws == '\r' || *ws ==' ' || *ws == '\n'))
486 		ws--;
487 
488 	// Set to first white space character, if we didn't get back to the start
489 	if (toEncode != ws)
490 		ws++;
491 
492 	// Now run through each character and encode if necessary
493 
494 	const XMLCh * i = toEncode;
495 
496 	if (*i == chPound) {
497 		// "#" Characters escaped at the start of a string
498 		result.sbXMLChAppendCh(chBackSlash);
499 	}
500 
501 	while (*i != chNull && i != ws) {
502 
503 		if (*i <= 0x09) {
504 			result.sbXMLChAppendCh(chBackSlash);
505 			result.sbXMLChAppendCh(chDigit_0);
506 			result.sbXMLChAppendCh(chDigit_0 + *i);
507 		}
508 		else if (*i <= 0x0f) {
509 			result.sbXMLChAppendCh(chBackSlash);
510 			result.sbXMLChAppendCh(chDigit_0);
511 			result.sbXMLChAppendCh(chLatin_A + *i);
512 		}
513 		else if (*i <= 0x19) {
514 			result.sbXMLChAppendCh(chBackSlash);
515 			result.sbXMLChAppendCh(chDigit_1);
516 			result.sbXMLChAppendCh(chDigit_0 + *i);
517 		}
518 		else if (*i <= 0x1f) {
519 			result.sbXMLChAppendCh(chBackSlash);
520 			result.sbXMLChAppendCh(chDigit_1);
521 			result.sbXMLChAppendCh(chLatin_A + *i);
522 		}
523 
524 		else if (*i == chComma) {
525 
526 			// Determine if this is an RDN separator
527 			const XMLCh *j = i;
528 			j++;
529 			while (*j != chComma && *j != chEqual && *j != chNull)
530 				j++;
531 
532 			if (*j != chEqual)
533 				result.sbXMLChAppendCh(chBackSlash);
534 
535 			result.sbXMLChAppendCh(*i);
536 
537 		}
538 
539 		else {
540 
541 			if (*i == chPlus ||
542 				*i == chDoubleQuote ||
543 				*i == chBackSlash ||
544 				*i == chOpenAngle ||
545 				*i == chCloseAngle ||
546 				*i == chSemiColon) {
547 
548 				result.sbXMLChAppendCh(chBackSlash);
549 			}
550 
551 			result.sbXMLChAppendCh(*i);
552 
553 		}
554 
555 		i++;
556 
557 	}
558 
559 	// Now encode trailing white space
560 	while (*i != chNull) {
561 
562 		if (*i == ' ')
563 			result.sbXMLChCat(s_strEncodedSpace);
564 		else
565 			result.sbXMLChAppendCh(*i);
566 
567 		i++;
568 
569 	}
570 
571 	return XMLString::replicate(result.rawXMLChBuffer());
572 
573 }
574 
decodeDName(const XMLCh * toDecode)575 XMLCh * decodeDName(const XMLCh * toDecode) {
576 
577 	// Take an encoded name and decode to a normal XMLCh string
578 
579 	XERCES_CPP_NAMESPACE_USE;
580 
581 	safeBuffer result;
582 
583 	result.sbXMLChIn(DSIGConstants::s_unicodeStrEmpty);
584 
585 	if (toDecode == NULL) {
586 		return NULL;
587 	}
588 
589 	const XMLCh * i = toDecode;
590 
591 	if (*i == chBackSlash && i[1] == chPound) {
592 
593 		result.sbXMLChAppendCh(chPound);
594 		i++;
595 		i++;
596 
597 	}
598 
599 	while (*i != chNull) {
600 
601 		if (*i == chBackSlash) {
602 
603 			i++;
604 
605 			if (*i == chDigit_0) {
606 
607 				i++;
608 
609 				if (*i >= chDigit_0 && *i <= chDigit_9) {
610 					result.sbXMLChAppendCh(*i - chDigit_0);
611 				}
612 				else if (*i >= chLatin_A && *i <= chLatin_F) {
613 					result.sbXMLChAppendCh(10 + *i - chLatin_A);
614 				}
615 				else if (*i >= chLatin_a && *i <= chLatin_f) {
616 					result.sbXMLChAppendCh(10 + *i - chLatin_a);
617 				}
618 				else {
619 					throw XSECException(XSECException::DNameDecodeError,
620 						"Unexpected escaped character in Distinguished name");
621 				}
622 			}
623 
624 			else if (*i == chDigit_1) {
625 
626 				i++;
627 
628 				if (*i >= chDigit_0 && *i <= chDigit_9) {
629 					result.sbXMLChAppendCh(16 + *i - chDigit_0);
630 				}
631 				else if (*i >= chLatin_A && *i <= chLatin_F) {
632 					result.sbXMLChAppendCh(26 + *i - chLatin_A);
633 				}
634 				else if (*i >= chLatin_a && *i <= chLatin_f) {
635 					result.sbXMLChAppendCh(26 + *i - chLatin_a);
636 				}
637 				else {
638 					throw XSECException(XSECException::DNameDecodeError,
639 						"Unexpected escaped character in Distinguished name");
640 				}
641 			}
642 
643 			else if (*i == chDigit_2) {
644 
645 				i++;
646 
647 				if (*i == '0') {
648 					result.sbXMLChAppendCh(' ');
649 				}
650 
651 				else {
652 					throw XSECException(XSECException::DNameDecodeError,
653 						"Unexpected escaped character in Distinguished name");
654 				}
655 
656 			}
657 
658 			else if (*i == chComma ||
659 					 *i == chPlus ||
660 					 *i == chDoubleQuote ||
661 					 *i == chBackSlash ||
662 					 *i == chOpenAngle ||
663 					 *i == chCloseAngle ||
664 					 *i == chSemiColon) {
665 
666 				result.sbXMLChAppendCh(*i);
667 			}
668 
669 			else {
670 
671 				throw XSECException(XSECException::DNameDecodeError,
672 					"Unexpected escaped character in Distinguished name");
673 
674 			}
675 
676 			i++;
677 
678 		}
679 
680 		else {
681 
682 			result.sbXMLChAppendCh(*i++);
683 
684 		}
685 
686 	}
687 
688 	return XMLString::replicate(result.rawXMLChBuffer());
689 
690 }
691 
692 // --------------------------------------------------------------------------------
693 //           Misc string functions
694 // --------------------------------------------------------------------------------
695 
696 // These three functions are pretty much lifted from XMLURL.cpp in Xerces
697 
isHexDigit(const XMLCh toCheck)698 static bool isHexDigit(const XMLCh toCheck)
699 {
700     if ((toCheck >= chDigit_0 && toCheck <= chDigit_9)
701     ||  (toCheck >= chLatin_A && toCheck <= chLatin_F)
702     ||  (toCheck >= chLatin_a && toCheck <= chLatin_f))
703     {
704         return true;
705     }
706     return false;
707 }
708 
xlatHexDigit(const XMLCh toXlat)709 static unsigned int xlatHexDigit(const XMLCh toXlat)
710 {
711 	if (!isHexDigit(toXlat)) {
712 		throw XSECException(XSECException::ErrorOpeningURI,
713 			"Unknown hex char");
714 	}
715     if ((toXlat >= chDigit_0) && (toXlat <= chDigit_9))
716         return (unsigned int)(toXlat - chDigit_0);
717 
718     if ((toXlat >= chLatin_A) && (toXlat <= chLatin_F))
719         return (unsigned int)(toXlat - chLatin_A) + 10;
720 
721     return (unsigned int)(toXlat - chLatin_a) + 10;
722 }
723 
cleanURIEscapes(const XMLCh * uriPath)724 XMLCh * cleanURIEscapes(const XMLCh * uriPath) {
725 
726     XMLByte *ptr, *utf8Path;
727     XMLSize_t len = XMLString::stringLen(uriPath);
728 
729     ptr = utf8Path = new XMLByte[len + 1];
730 
731     for (XMLSize_t i = 0; i < len; i++) {
732         unsigned int value = uriPath[i];
733 
734         if (value > 255) {
735             delete[] utf8Path;
736             throw XSECException(XSECException::ErrorOpeningURI, "Wide character in URI");
737         }
738 
739         if (value == chPercent) {
740             if (!(i + 2 < len && isHexDigit(uriPath[i + 1]) && isHexDigit(uriPath[i + 2]))) {
741                 delete[] utf8Path;
742                 throw XSECException(XSECException::ErrorOpeningURI, "Bad escape sequence in URI");
743             }
744 
745             value = (xlatHexDigit(uriPath[i + 1]) * 16) + (xlatHexDigit(uriPath[i + 2]));
746             i += 2;
747         }
748 
749         *(ptr++) = (XMLByte) value;
750     }
751     *ptr = 0;
752 
753     try {
754         XMLCh* unicodePath = transcodeFromUTF8(utf8Path);
755         delete[] utf8Path;
756         return unicodePath;
757     }
758     catch (const XMLException&) {
759     }
760 
761     delete[] utf8Path;
762     throw XSECException(XSECException::ErrorOpeningURI, "Failed to transcode URI from UTF-8");
763 }
764 
765 // --------------------------------------------------------------------------------
766 //           Generate Ids
767 // --------------------------------------------------------------------------------
768 
makeHexByte(XMLCh * h,unsigned char b)769 void makeHexByte(XMLCh * h, unsigned char b) {
770 
771 	unsigned char toConvert =  (b & 0xf0);
772 	toConvert = (toConvert >> 4);
773 
774 	if (toConvert < 10)
775 		h[0] = chDigit_0 + toConvert;
776 	else
777 		h[0] = chLatin_a + toConvert - 10;
778 
779 	toConvert =  (b & 0xf);
780 
781 	if (toConvert < 10)
782 		h[1] = chDigit_0 + toConvert;
783 	else
784 		h[1] = chLatin_a + toConvert - 10;
785 
786 }
787 
788 
generateId(unsigned int bytes)789 XMLCh * generateId(unsigned int bytes) {
790 
791 	unsigned char b[128];
792 	XMLCh id[258];
793 	unsigned int toGen = (bytes > 128 ? 16 : bytes);
794 
795 	// Get the appropriate amount of random data
796 	// Need to zeroise to ensure valgrind is happy
797 	memset(b, 0, 128);
798 	memset(id, 0, sizeof(id));
799 	if (XSECPlatformUtils::g_cryptoProvider->getRandom(b, toGen) != toGen) {
800 
801 		throw XSECException(XSECException::CryptoProviderError,
802 			"generateId - could not obtain enough random");
803 
804 	}
805 
806 	id[0] = chLatin_I;
807 
808 	unsigned int i;
809 	for (i = 0; i < toGen; ++i) {
810 
811 		makeHexByte(&id[1+(i*2)], b[i]);
812 
813 	}
814 
815 	id[1+(i*2)] = chNull;
816 
817 	return XMLString::replicate(id);
818 
819 }
820 
821