def _send_msg(self, message, msgid): ''' Send one message using stomppy. The message will be signed using the host cert and key. If an encryption certificate has been supplied, the message will also be encrypted. ''' log.info('Sending message: %s', msgid) headers = { 'destination': self._dest, 'receipt': msgid, 'empa-id': msgid } if message is not None: to_send = crypto.sign(message, self._cert, self._key) if self._enc_cert is not None: to_send = crypto.encrypt(to_send, self._enc_cert) else: to_send = '' try: # Try using the v4 method signiture self._conn.send(self._dest, to_send, headers=headers) except TypeError: # If it fails, use the v3 metod signiture self._conn.send(to_send, headers=headers)
def test_message_tampering(self): """Test that a tampered message is not accepted as valid.""" signed_message = sign(MSG, TEST_CERT_FILE, TEST_KEY_FILE) tampered_message = signed_message.replace(MSG, "Spam") # Verifying the orignal, un-tampered message should be fine. verified_message, verified_signer = verify(signed_message, TEST_CA_DIR, False) self.assertEqual(verified_message, MSG) self.assertEqual(verified_signer, TEST_CERT_DN) # Verifying the tampered message should not be fine. self.assertRaises(CryptoException, verify, tampered_message, TEST_CA_DIR, False)
def test_get_signer_cert(self): ''' Check that the certificate retrieved from the signed message matches the certificate used to sign it. ''' signed_msg = sign(MSG, TEST_CERT_FILE, TEST_KEY_FILE) cert = get_signer_cert(signed_msg) # Remove any information preceding the encoded certificate. cert = cert[cert.find('-----BEGIN'):] with open(TEST_CERT_FILE, 'r') as test_cert: cert_string = test_cert.read() if cert.strip() != cert_string.strip(): self.fail('Certificate retrieved from signature ' 'does not match certificate used to sign.')
def _send_msg(self, message, msgid): """ Send one message using stomppy. The message will be signed using the host cert and key. If an encryption certificate has been supplied, the message will also be encrypted. """ log.info("Sending message: " + msgid) headers = {"destination": self._dest, "receipt": msgid, "empa-id": msgid} if message is not None: to_send = crypto.sign(message, self._cert, self._key) if self._enc_cert is not None: to_send = crypto.encrypt(to_send, self._enc_cert) else: to_send = "" self._conn.send(to_send, headers=headers)
def _send_msg(self, message, msgid): ''' Send one message using stomppy. The message will be signed using the host cert and key. If an encryption certificate has been supplied, the message will also be encrypted. ''' log.info('Sending message: %s', msgid) headers = {'destination': self._dest, 'receipt': msgid, 'empa-id': msgid} if message is not None: to_send = crypto.sign(message, self._cert, self._key) if self._enc_cert is not None: to_send = crypto.encrypt(to_send, self._enc_cert) else: to_send = '' self._conn.send(to_send, headers=headers)
def _send_msg_ams(self, text, msgid): """Send one message using AMS, returning the AMS ID of the mesage. The message will be signed using the host cert and key. If an encryption certificate has been supplied, the message will also be encrypted. """ log.info('Sending message: %s', msgid) if text is not None: # First we sign the message to_send = crypto.sign(text, self._cert, self._key) # Possibly encrypt the message. if self._enc_cert is not None: to_send = crypto.encrypt(to_send, self._enc_cert) # Then we need to wrap text up as an AMS Message. message = AmsMessage(data=to_send, attributes={'empaid': msgid}).dict() argo_response = self._ams.publish(self._dest, message, retry=3) return argo_response['messageIds'][0]
def test_sign(self): ''' I haven't found a good way to test this yet. Each time you sign a message, the output has a random element, so you can't compare strings. ''' signed = sign(MSG, self.certpath, self.keypath) if not 'MIME-Version' in signed: self.fail("Didn't get MIME message when signing.") if not MSG in signed: self.fail('The plaintext should be included in the signed message.') # Indirect testing, using the verify_message() method retrieved_msg, retrieved_dn = verify(signed, self.ca_dir, False) if not retrieved_dn == TEST_CERT_DN: self.fail("The DN of the verified message didn't match the cert.") if not retrieved_msg == MSG: self.fail("The verified message didn't match the original.")
def _send_msg(self, message, msgid): ''' Send one message using stomppy. The message will be signed using the host cert and key. If an encryption certificate has been supplied, the message will also be encrypted. ''' log.info('Sending message: ' + msgid) headers = { 'destination': self._dest, 'receipt': msgid, 'empa-id': msgid } if message is not None: to_send = crypto.sign(message, self._cert, self._key) if self._enc_cert is not None: to_send = crypto.encrypt(to_send, self._enc_cert) else: to_send = '' self._conn.send(to_send, headers=headers)
def test_sign(self): ''' I haven't found a good way to test this yet. Each time you sign a message, the output has a random element, so you can't compare strings. ''' signed = sign(MSG, TEST_CERT_FILE, TEST_KEY_FILE) if not 'MIME-Version' in signed: self.fail("Didn't get MIME message when signing.") if not MSG in signed: self.fail( 'The plaintext should be included in the signed message.') # Indirect testing, using the verify_message() method retrieved_msg, retrieved_dn = verify(signed, TEST_CA_DIR, False) if not retrieved_dn == TEST_CERT_DN: self.fail("The DN of the verified message didn't match the cert.") if not retrieved_msg == MSG: self.fail("The verified message didn't match the original.")
def test_verify(self): signed_msg = sign(MSG, TEST_CERT_FILE, TEST_KEY_FILE) # This is a manual 'fudge' to make MS2 appear like a # quoted-printable message when signed # Encode MSG2 so it's 'quoted-printable' quopri_msg = quopri.encodestring(MSG2) # Add Content-Type and Content-Transfer-Encoding # headers to message header_quopri_msg = ('Content-Type: text/xml; charset=utf8\n' 'Content-Transfer-Encoding: quoted-printable\n' '\n' '%s' % quopri_msg) # We can't use crypto.sign as that assumes the use of the '-text' option # which cause the message to be interpreted as plaintext p1 = Popen([ 'openssl', 'smime', '-sign', '-inkey', TEST_KEY_FILE, '-signer', TEST_CERT_FILE ], stdin=PIPE, stdout=PIPE, stderr=PIPE) signed_msg2, error = p1.communicate(header_quopri_msg) if error != '': self.fail(error) retrieved_msg, retrieved_dn = verify(signed_msg, TEST_CA_DIR, False) if not retrieved_dn == TEST_CERT_DN: self.fail("The DN of the verified message didn't match the cert.") if not retrieved_msg.strip() == MSG: self.fail("The verified messge didn't match the original.") retrieved_msg2, retrieved_dn2 = verify(signed_msg2, TEST_CA_DIR, False) if not retrieved_dn2 == TEST_CERT_DN: print retrieved_dn2 print TEST_CERT_DN self.fail("The DN of the verified message didn't match the cert.") if not retrieved_msg2.strip() == MSG2: print retrieved_msg2 print MSG2 self.fail("The verified messge didn't match the original.") # Try empty string try: verify('', TEST_CA_DIR, False) except CryptoException: pass # Try rubbish try: verify('Bibbly bobbly', TEST_CA_DIR, False) except CryptoException: pass # Try None arguments try: verify('Bibbly bobbly', None, False) except CryptoException: pass try: verify(None, 'not a path', False) except CryptoException: pass
def test_verify(self): signed_msg = sign(MSG, TEST_CERT_FILE, TEST_KEY_FILE) # This is a manual 'fudge' to make MS2 appear like a # quoted-printable message when signed # Encode MSG2 so it's 'quoted-printable', after encoding it to ensure # it's a bytes object for Python 3. Latter is a no-op in Python 2. quopri_msg = quopri.encodestring(MSG2.encode()) # In Python 3, encodestring() returns bytes so decode to a string while # Python 2 compatability is still required. if not isinstance(quopri_msg, str): quopri_msg = quopri_msg.decode() # Add Content-Type and Content-Transfer-Encoding # headers to message header_quopri_msg = ('Content-Type: text/xml; charset=utf8\n' 'Content-Transfer-Encoding: quoted-printable\n' '\n' '%s' % quopri_msg) # We can't use crypto.sign as that assumes the use of the '-text' option # which cause the message to be interpreted as plaintext p1 = Popen([ 'openssl', 'smime', '-sign', '-inkey', TEST_KEY_FILE, '-signer', TEST_CERT_FILE ], stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True) signed_msg2, error = p1.communicate(header_quopri_msg) if error != '': self.fail(error) retrieved_msg, retrieved_dn = verify(signed_msg, TEST_CA_DIR, False) if not retrieved_dn == TEST_CERT_DN: self.fail("The DN of the verified message didn't match the cert.") if not retrieved_msg.strip() == MSG: self.fail("The verified messge didn't match the original.") retrieved_msg2, retrieved_dn2 = verify(signed_msg2, TEST_CA_DIR, False) if not retrieved_dn2 == TEST_CERT_DN: print(retrieved_dn2) print(TEST_CERT_DN) self.fail("The DN of the verified message didn't match the cert.") if not retrieved_msg2.strip() == MSG2: print(retrieved_msg2) print(MSG2) self.fail("The verified messge didn't match the original.") # Try empty string try: verify('', TEST_CA_DIR, False) except CryptoException: pass # Try rubbish try: verify('Bibbly bobbly', TEST_CA_DIR, False) except CryptoException: pass # Try None arguments try: verify('Bibbly bobbly', None, False) except CryptoException: pass try: verify(None, 'not a path', False) except CryptoException: pass
def send_all(self): ''' Send all the messages in the outgoing queue. Either via STOMP or HTTPS (to an Argo Message Broker). ''' log.info('Found %s messages.', self._outq.count()) for msgid in self._outq: if not self._outq.lock(msgid): log.warn('Message was locked. %s will not be sent.', msgid) continue text = self._outq.get(msgid) if self._protocol == Ssm2.STOMP_MESSAGING: # Then we are sending to a STOMP message broker. self._send_msg(text, msgid) log.info('Waiting for broker to accept message.') while self._last_msg is None: if not self.connected: raise Ssm2Exception('Lost connection.') log_string = "Sent %s" % msgid elif self._protocol == Ssm2.AMS_MESSAGING: # Then we are sending to an Argo Messaging Service instance. if text is not None: # First we sign the message to_send = crypto.sign(text, self._cert, self._key) # Possibly encrypt the message. if self._enc_cert is not None: to_send = crypto.encrypt(to_send, self._enc_cert) # Then we need to wrap text up as an AMS Message. message = AmsMessage(data=to_send, attributes={ 'empaid': msgid }).dict() argo_response = self._ams.publish(self._dest, message) argo_id = argo_response['messageIds'][0] log_string = "Sent %s, Argo ID: %s" % (msgid, argo_id) else: # The SSM has been improperly configured raise Ssm2Exception('Unknown messaging protocol: %s' % self._protocol) time.sleep(0.1) # log that the message was sent log.info(log_string) self._last_msg = None self._outq.remove(msgid) log.info('Tidying message directory.') try: # Remove empty dirs and unlock msgs older than 5 min (default) self._outq.purge() except OSError, e: log.warn('OSError raised while purging message queue: %s', e)
def test_verify(self): signed_msg = sign(MSG, TEST_CERT_FILE, TEST_KEY_FILE) # This is a manual 'fudge' to make MS2 appear like a # quoted-printable message when signed # Encode MSG2 so it's 'quoted-printable' quopri_msg = quopri.encodestring(MSG2) # Add Content-Type and Content-Transfer-Encoding # headers to message header_quopri_msg = ('Content-Type: text/xml; charset=utf8\n' 'Content-Transfer-Encoding: quoted-printable\n' '\n' '%s' % quopri_msg) # We can't use crypto.sign as that assumes the use of the '-text' option # which cause the message to be interpreted as plaintext p1 = Popen(['openssl', 'smime', '-sign', '-inkey', TEST_KEY_FILE, '-signer', TEST_CERT_FILE], stdin=PIPE, stdout=PIPE, stderr=PIPE) signed_msg2, error = p1.communicate(header_quopri_msg) if error != '': self.fail(error) retrieved_msg, retrieved_dn = verify(signed_msg, TEST_CA_DIR, False) if not retrieved_dn == TEST_CERT_DN: self.fail("The DN of the verified message didn't match the cert.") if not retrieved_msg.strip() == MSG: self.fail("The verified messge didn't match the original.") retrieved_msg2, retrieved_dn2 = verify(signed_msg2, TEST_CA_DIR, False) if not retrieved_dn2 == TEST_CERT_DN: print retrieved_dn2 print TEST_CERT_DN self.fail("The DN of the verified message didn't match the cert.") if not retrieved_msg2.strip() == MSG2: print retrieved_msg2 print MSG2 self.fail("The verified messge didn't match the original.") # Try empty string try: verify('', TEST_CA_DIR, False) except CryptoException: pass # Try rubbish try: verify('Bibbly bobbly', TEST_CA_DIR, False) except CryptoException: pass # Try None arguments try: verify('Bibbly bobbly', None, False) except CryptoException: pass try: verify(None, 'not a path', False) except CryptoException: pass