def get_certs(self, host=None, port=None, **kwargs):
		"""Returns XML response containing certificate data and their
		timestamps. Only leaf (EE) certificates are included, not the
		whole chain.
		
		@param host: hostname
		@param port: port where service runs
		"""
		if (host is None or port is None):
			raise cherrypy.HTTPError(400)
		try:
			host_port = str(host + ":" + port)
			service_id = notary_common.ObservedServer(host_port)
		except ValueError:
			raise cherrypy.HTTPError(400)
		
		logger.info("Certs request '%s'" % service_id)
		ee_certs = notary_common.get_ee_certs(service_id)
		
		if len(ee_certs) == 0:
			self.launch_on_demand_probe(service_id)
			raise cherrypy.HTTPError(404)
		
		to_be_signed = host_port
		#Data to be signed are simple concatenation of following:
		# - service_id as string in the form 'host:port'
		#Then, for each 'certificate' element, following attributes
		#(ints are network order):
		# - DER encoded cert body, uint32 start, uint32 end
		
		dom_impl = getDOMImplementation() 
		new_doc = dom_impl.createDocument(None, "notary_reply", None) 
		top_element = new_doc.documentElement
		top_element.setAttribute("version", "1")
		top_element.setAttribute("sig_type", "rsa-sha256")
	
		for ee_cert in ee_certs:
			cert_elem = new_doc.createElement("certificate")
			top_element.appendChild(cert_elem)
			
			cert_elem.setAttribute("body", base64.standard_b64encode(ee_cert.cert))
			to_be_signed += ee_cert.cert
			
			cert_elem.setAttribute("start", str(ee_cert.start_ts))
			cert_elem.setAttribute("end", str(ee_cert.end_ts))
			to_be_signed += struct.pack("!2I", ee_cert.start_ts, ee_cert.end_ts)
			
		sig = self.sign_rsa_base64(to_be_signed, digest="sha256")
		top_element.setAttribute("sig", sig)
		
		cherrypy.response.headers['Content-Type'] = 'text/xml'
		
		return new_doc.toprettyxml()
	def get_xml(self, service_id):
		"""Return xml with certificates' fingerprints.
		@param service_id: requested service
		@type service_id: notary_common.ObservedServer
		"""
		logger.info("Request for '%s'" % service_id)
		
		ee_certs = notary_common.get_ee_certs(service_id)
		
		ee_certs_by_key = {}
		keys = []

		for ee_cert in ee_certs:
			md5_fp = hashlib.md5(ee_cert.cert).digest()
			
			k = md5_fp
			if k not in ee_certs_by_key:
				ee_certs_by_key[k] = []
				keys.append(k)
			ee_certs_by_key[k].append(ee_cert)
		
		#If we have no record of the service_id, launch a on-demand
		#scan, but only if the scan for the same service_id is not
		#already scheduled or being scanned.
		#Perspectives Firefox extensions likes to fire 3 requests
		#often faster than we get the scan results, so this way we won't
		#clog up the queue with unnecessary scans.
		if len(ee_certs) == 0:
			self.launch_on_demand_probe(service_id)
			# return 404, assume client will re-query
			raise cherrypy.HTTPError(404)
	
		dom_impl = getDOMImplementation() 
		new_doc = dom_impl.createDocument(None, "notary_reply", None) 
		top_element = new_doc.documentElement
		top_element.setAttribute("version", "1") 
		top_element.setAttribute("sig_type", "rsa-md5") 
	
		## Packed data format:
		#service-id (variable length, terminated with null-byte) 
		#num_timespans (2-bytes)
		#key_len_bytes (2-bytes, 16 for version 1 - md5 only)
		#key type (1-byte), always has a value of 3 for SSL 
		#key (md5) data (length specified in key_len_bytes)
		#list of timespan start,end pairs  (length is 2 * 4 * num_timespans)
		packed_data = ""
	
		for k in keys:
			md5_fp = k
			key_elem = new_doc.createElement("key")
			key_elem.setAttribute("type","ssl")
			
			fp_len = len(md5_fp)
			fp_bytes = md5_fp
			
			key_elem.setAttribute("fp", self._unpack_hex_with_colons(md5_fp))
			
			top_element.appendChild(key_elem)
			num_timespans = len(ee_certs_by_key[k])
			
			TYPE_SSL = 3 #from FF extension's comments
			head = struct.pack("!2HB", num_timespans, fp_len, TYPE_SSL)
			ts_bytes = ""
			for ee_cert in sorted(ee_certs_by_key[k], key=lambda ee_cert: ee_cert.start_ts):
				ts_start = ee_cert.start_ts
				ts_end	= ee_cert.end_ts
				ts_elem = new_doc.createElement("timestamp")
				ts_elem.setAttribute("end",str(ts_end))
				ts_elem.setAttribute("start", str(ts_start))
				key_elem.appendChild(ts_elem) 
				ts_bytes += struct.pack("!I", ts_start)
				ts_bytes += struct.pack("!I", ts_end)
			packed_data =(head + fp_bytes + ts_bytes) + packed_data   
	
		packed_data = service_id.old_str() + struct.pack("B", 0) + packed_data 
	
		sig = self.sign_rsa_base64(packed_data, digest="md5")
		top_element.setAttribute("sig",sig)
		return top_element.toprettyxml()