Home | History | Annotate | Download | only in network_DestinationVerification
      1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import base64
      6 import json
      7 import logging
      8 import os.path
      9 import tempfile
     10 
     11 import common
     12 from autotest_lib.client.bin import test
     13 from autotest_lib.client.common_lib import error
     14 from autotest_lib.client.common_lib import utils
     15 
     16 # This modifies the include path to include the shill test-scripts.
     17 # pylint: disable=W0611
     18 from autotest_lib.client.cros import flimflam_test_path
     19 # pylint: enable=W0611
     20 import crypto_util_pb2
     21 
     22 
     23 TEST_DATA1 = """{
     24     "connected":false,
     25     "debug_build":true,
     26     "has_update":false,
     27     "hotspot_bssid":"00:1A:11:FF:AC:DF",
     28     "locale":"en_US",
     29     "location": {
     30         "latitude":37.4193105,
     31         "longitude":-122.07878869999999
     32     },
     33     "mac_address":"4C:AA:16:A5:AC:DF",
     34     "name":"eureka8997",
     35     "public_key":"MIGJAoGBAK3SXmWZBOhJibv8It05qIbgHXXhnCXxHkW+C6jNMHR5sZgDpFaOY1xwXERjKdJxcwrEy3VAT5Uv9MgHPBvxxJku76HYh1yVfIw1rhLnHBTHSxwUzJNCrgc3l3t/UACacLjVNIzccDpYf2vnOcA+t1t6IXRjzuU2NdwY4dJXNtWPAgMBAAE=",
     36     "setup_state":11,
     37     "sign": {
     38         "certificate":"-----BEGIN CERTIFICATE-----\\nMIIDhzCCAm8CBFE2SCMwDQYJKoZIhvcNAQEFBQAwfTELMAkGA1UEBhMCVVMxEzAR\\nBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzARBgNV\\nBAoMCkdvb2dsZSBJbmMxEjAQBgNVBAsMCUdvb2dsZSBUVjEYMBYGA1UEAwwPRXVy\\nZWthIEdlbjEgSUNBMB4XDTEzMDMwNTE5MzE0N1oXDTMzMDIyODE5MzE0N1owgYMx\\nFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxEjAQBgNVBAsTCUdvb2dsZSBUVjETMBEG\\nA1UEChMKR29vZ2xlIEluYzETMBEGA1UECBMKQ2FsaWZvcm5pYTELMAkGA1UEBhMC\\nVVMxHjAcBgNVBAMUFWV2dF9lMTYxIDAwMWExMWZmYWNkZjCCASIwDQYJKoZIhvcN\\nAQEBBQADggEPADCCAQoCggEBAPHGDV0lLoTYK78q13y/2u77YTjgbBlWAOxgrSNc\\nMmGHx1K0aPyo50p99dGQnjapW6jtGrMzReWV2Wz3VL8rYlqY7oWjeJwsLQwo2tcn\\n7vIZ/PuvPz9xgnGMUbBOfhCf3Epb1N4Jz82pxxrOFhUawWAglC9C4fUeZLCZpOJs\\nQd4QeAznkydl3xbqdSm74kwxE6vkGEzSCDnC7aYx0Rvvr1mZOKdl4AinYrxzWgmV\\nsTnaFT1soSjmC5e/i6Jcrs4dDFgY6mKy9Qtly2XPSCYljm6L4SgqgJNmlpY0qYJg\\nO++BdofIbU2jsOiCMvIuKkbMn72NsPQG0QhnVMwk7kYg6kkCAwEAAaMNMAswCQYD\\nVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEAW0bQl9yjBc7DgMp94i7ZDOUxKQrz\\nthephuwzb3/wWiTHcw6KK6FRPefXn6NPWxKKeQmv/tBxHbVlmYRXUbrhksnD0aUk\\ni4InvtL2m0H1fPfMxmJRFE+HoSXu+s0sGON831JaMcYRbAku5uHnltaGNzOI0KPH\\nFGoCDmjAZD+IuoR2LR4FuuTrECK7KLjkdf//z5d5j7nBDPZS7uTCwC/BwM9asRj3\\ntJA5VRFbLbsit1VI7IaRCk9rsSKkpBUaVeKbPLz+y/Z6JonXXT6AxsfgUSKDd4B7\\nMYLrTwMQfGuUaaaKko6ldKIrovjrcPloQr1Hxb2bipFcjLmG7nxQLoS6vQ==\\n-----END CERTIFICATE-----\\n",
     39         "nonce":"+6KSGuRu833m1+TP",
     40         "signed_data":"vwMBgANrp5XpCswLyk/OTXT56ORPeIWjH7xAdCk3qgjkwI6+8o56zJS02+tC5hhIHWh7oppTmWYF4tKvBQ3GeCz7IW9f7HWDMtO7x7yRWxzJyehaJbCfXvLdfs0/WKllzvGVBgNpcIAwU2NSFUG/jpXclntFzds0EUJG9wHxS6PXXSYRu+PlIFdCDcQJsUlnwO9AGFOJRV/aARGh8YUTWCFIQPOtPEqT5eegt+TLf01Gq0YcrRwSTKy1I3twOnWiMfIdkJdQKPtBwwbvuAyGuqYFocfjKABbnH9Tvl04yyO3euKbYlSqaF/l8CXmzDJTyO7tDOFK59bV9auE4KljrQ=="
     41     },
     42     "ssdp_udn":"c5b2a83b-5958-7ce6-b179-e1f44699429b",
     43     "ssid":"",
     44     "timezone":"America/Los_Angeles",
     45     "uptime":1991.7,
     46     "version":4,
     47     "wpa_configured":false,
     48     "wpa_state":1
     49 } """
     50 TEST_DATA2 = """{
     51     "connected": false,
     52     "debug_build": true,
     53     "has_update": false,
     54     "hotspot_bssid": "00:1A:11:FF:AC:1E",
     55     "ip_address": "192.168.43.32",
     56     "locale": "en_US",
     57     "mac_address": "B0:EE:45:49:AC:1E",
     58     "name": "Greg's Eureka",
     59     "noise_level": -85,
     60     "public_key": "MIGJAoGBAOe+6bF51A7wFVMbyPiHYLdgAmP6sdhOUohqCHn4qHSfDY41AbAbVmXLbUZ5BF2KSdDYqU4fAXoaI8V8D5DRWh57Ax10Sl1/6M1u22KT6FYQyUToXGPcXldBzRRMok8H4XyiebDVevjvvV6yuABSYYhfSlrMdGj8qxRVwTxx0CItAgMBAAE=",
     61     "release_track": "beta-channel",
     62     "setup_state": 50,
     63     "sign": {
     64         "certificate": "-----BEGIN CERTIFICATE-----\\nMIIDejCCAmICBFEtN4wwDQYJKoZIhvcNAQEFBQAwfTELMAkGA1UEBhMCVVMxEzAR\\nBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzARBgNV\\nBAoMCkdvb2dsZSBJbmMxEjAQBgNVBAsMCUdvb2dsZSBUVjEYMBYGA1UEAwwPRXVy\\nZWthIEdlbjEgSUNBMB4XDTEzMDIyNjIyMzAzNloXDTMzMDIyMTIyMzAzNlowdzET\\nMBEGA1UECBMKQ2FsaWZvcm5pYTELMAkGA1UEBhMCVVMxFjAUBgNVBAcTDU1vdW50\\nYWluIFZpZXcxEjAQBgNVBAsTCUdvb2dsZSBUVjETMBEGA1UEChMKR29vZ2xlIElu\\nYzESMBAGA1UEAxQJZXZ0X2UxMjYyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\\nCgKCAQEAo7Uu+bdyCjtiUYpmNU4ZvRjDg6VkEh/g0YPDG2pICBU4XKvsqHH1i0hb\\ntWp1J79hV9Rqst1yHT02Oeh3o1SOd2zeamYzmvXRVN7AZqfQlzWxwxk/ltpXGwew\\nm+EIR2bP4kpvyEKvvziTMtTxviOK+A395QyodMhMXClKTus/Gme2r1fBoQqJJR/z\\nrmwXCsl5kpdhj7FOIII3BCYV0zejjQquzywjsKfCVON28VGgJdaKgmXxkeRYYWVN\\nnuTNna57vXe16FP6hS1ty1U77ESffLTpNJ/M4tsd2dMVVTDuGeX3q8Ix4TN8cqpq\\nu1AKEf59hygys9j6cHZRKR/div0+uQIDAQABow0wCzAJBgNVHRMEAjAAMA0GCSqG\\nSIb3DQEBBQUAA4IBAQAZx6XyEK9SLHE+rbKCVsLN9+hTEa50aikPmxOZt+lFuB4+\\nVJZ/GCPQCZJIde2tlWUe2YBgoZw2xUKgIsM3Yq42Gawi35/oZ3qycTgYU8KJP9kU\\nMbYNAH90mz9BDH7MmnRID5dFexHyBCG88EJ+ZvxmUVn0EVDcsSMt11wIAZ/T+/gs\\nE1120d/GxhjYQ9YZz7SZXBQfRdqCdcPNl2+QSHHl+WvYLzdJa2xYj39/kQu47Vp7\\nX5rZrHSBvzdVymH0Od2D18t+Q6lxbSdyUNhP1MVhdkT1Ct4OmRS3FJ4aannXMhfq\\nNg7k4Sfif5iktYT4VRKpThe0EGJNfqKJKYtvHEVC\\n-----END CERTIFICATE-----\\n",
     65         "nonce": "pTwRhdsB5cb3Ev8o",
     66         "signed_data": "WIvN6Ujo4CoxUNcsm1YaLRUe1KJVEG+oXorUBJae/fKQrLfnH9ChDfxzW+EDZlLBLPk9u5EAptr8LKK6AunbBTDIeBkjzXv3nS+xlmV9ZdA71imitva88HPzC+a2H61dJL8puNbZu9j1Zs3sCybw2F+qZbDBhbG0sJTEXytPjewqAl8iBZSAS0BoNJZYA7Q/bCPI07pg404pI392cKP8FYJR08Y4xoV94Em+jnZ2nZabSsmsScYGvpWVNeS2z+f0to6ureOxaqgT+AAckqtCRcHd66QtLGwKXWviaevKte1z185f4r55U4P5pkQi+xd6lZRsMQydwUzLxgk7UY5U3Q=="
     67     },
     68     "signal_level": -42,
     69     "ssdp_udn": "cd7c1f15-2f49-076b-51ac-9d651872c784",
     70     "ssid": "Greg's Phone",
     71     "timezone": "America/Los_Angeles",
     72     "uptime": 207.33,
     73     "version": 4,
     74     "wpa_configured": true,
     75     "wpa_id": 0,
     76     "wpa_state": 10
     77 }
     78 """
     79 TEST_DATA3 = """{
     80     "build_version":"10566",
     81     "connected":false,
     82     "has_update":false,
     83     "hotspot_bssid":"FA:8F:CA:30:08:26",
     84     "locale":"en_US",
     85     "mac_address":"B0:EE:45:68:B5:52",
     86     "name":"Chromekey Greg",
     87     "public_key":"MIIBCgKCAQEApQoxFRJWEP9Oa+lSF2PCMBCpd2LYeyPMHjVKCF2IlrGbrgQ3U9wI6tBvLkHg570KSA6onL/7e9J31RLwA8gIE0zJ9M7NToxj1cVa8jOqXPIllJP7uY/TmtMIwCvuMCu6KBNW/wzKK6jkT7wScwrPJscmwWr/0h6lKXZrv0DhwvVv3i6VGsasZzVYlOoZ7eRe1OHiJgehPFUh0Vp7lVRDzumtJ0N6hybWP/Ap6dNlcO9Hq67bljHRrgwuBT2iRJBIdZt6m4xZlf78dH6Y2gfeQ3GBtDZWbZ5v6hzaYeIxlMTelz6ZlEQa0fPegK1dsxCddvLhRCDQr2bZlwyRdof6uwIDAQAB",
     88     "release_track":"beta-channel",
     89     "setup_state":11,
     90     "sign": {
     91         "certificate": "-----BEGIN CERTIFICATE-----\\nMIIDpjCCAo4CBFFfTz8wDQYJKoZIhvcNAQEFBQAwfTELMAkGA1UEBhMCVVMxEzAR\\nBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzARBgNV\\nBAoMCkdvb2dsZSBJbmMxEjAQBgNVBAsMCUdvb2dsZSBUVjEYMBYGA1UEAwwPRXVy\\nZWthIEdlbjEgSUNBMB4XDTEzMDQwNTIyMjUwM1oXDTMzMDMzMTIyMjUwM1owgYAx\\nCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQKEwpHb29n\\nbGUgSW5jMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRIwEAYDVQQLEwlHb29nbGUg\\nVFYxGzAZBgNVBAMTElpaQUlNIEZBOEZDQTMwMDgyNjCCASIwDQYJKoZIhvcNAQEB\\nBQADggEPADCCAQoCggEBALmAGRcIQt/k7WfoUHDCWQhzQ/FrHDnNiHcVj09Tyu7/\\n2pIB+pVnLac8pfFwdVAcDG4xmjnROIHeajz627uq8bHEVDfPCHe8WiM+CsPrMC85\\nlQOq8rBwNw3WO82suvWL8wjdqFy0uQHajp9e9ix3FXzfZDAuf7ABHmVZnPMWQz0a\\nR3zDCCF2NhEVhBwq+IGKNNvuIPhVF/5tkdWPmihFukJabmV2kjFUuPbEf4T1OMu+\\nhyqZ+lsTc/XVIqICRIq9ZE36MquAw0g9Hoah8OFFpkq2xJqlCY+HKvdhiA1HybfY\\nXSxOsI2rTQk3YHFMrAGMu16UYuOA+CRHD+UC8SI0fqkCAwEAAaMvMC0wCQYDVR0T\\nBAIwADALBgNVHQ8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcN\\nAQEFBQADggEBAJGyWBoDvwZBlDcyX31l5kwGVf6nVZR4KedcQMGpm76C6fgzeLHt\\nAq7OQhZgifFVLvzG7kqYgRRsW7WQKTF/QmHn8rnCdY16YtZv3vFzLbdBWkmSqAxD\\nqmBum9oD74AYeJaR0v68KCGvAVG0juRSs3H93s8k/fhY+LespUMlHwB4DwRYxDNP\\nIu3HX8NEmOBwjodKDDa8yu1weYUf8GFXH3b+tu7IHRzQpPzbSSibs+AXc8WbJWk3\\nrtQSugqegiiM/OAdRuSvkXtc1DJP9F7OLsVpF9i/VZ2k/QDPCu06vXB2w3wlRyR3\\nf6nQGB1Ej8Klsxlo8B+rmQ6N8C7f48GMI8s=\\n-----END CERTIFICATE-----\\n",
     92         "nonce": "E1oqNODwWVIfSjUs",
     93         "signed_data": "aaT56/P7KiMxVbWCedpSNIikpxh0EzdjgEuP153pCNfYys2KmlVtvEnXeFGYKJP2ypsX0qx/9Bx2C18T8HZ4PvNW0fUEheScvkzbDTn/gBpwUJv3XT+55XneUdjIAQu83qNR/AjxYa9cDGzxbnZJL91Fd1Grw/fNaKEMiedWRiESABQREiS2OW+iZ3Z/JRs99o4M6m+6f/mvNkgZ3GrFxNnPEXe7g1sYjspPhnDLvASNzd9j24YIxu+PTWZCNL6clps+/ghNA/0fB3PBDILrcGnER36Vc8gNhjD1r1f/ACU1qk06yMNC/Kgt2pMQkpjaXby+B75Z9yrogNHs4f5tIA=="
     94     },
     95     "ssdp_udn":"b91027b5-f19e-7df6-6533-5056ad190575",
     96     "ssid":"Greg's Phone",
     97     "uptime":262650.75,
     98     "version":4,
     99     "wpa_configured":false,
    100     "wpa_id":0,
    101     "wpa_state":1
    102 }"""
    103 # This is just a DER formatted public key with the first 22 bytes stripped.
    104 # Technically, this is called RSAPublicKey format.
    105 ENCRYPTION_PUBLIC_KEY = (
    106     '0\x81\x89\x02\x81\x81\x00\xd4\xe3z\x82\x0b6D\x8a\x1dY'
    107     '\x1d\xdel\xbf\xad,\r\x8b\xefm\xe3\xbd\xef<\x954\x96C<'
    108     '\x9e\x7fB\xef\xe8&h\xfb\xc4Z\x0e\x196C\x1d\xd7f\x88\\5'
    109     '\xd5\x1e\xb8\xe0\x8d\xc4\xbc\xd1\xb3\xc4\xd3)!7\xd2{'
    110     '\x11\x89\t\xfb\x8d\xe8\xbaRL\xacI\xf2\x0f.JB\x8e\xd4'
    111     '\xdc\xc2\x81v6\x8a\x154\xbe8\xfc\xa8\x84zH\xf0j\x87('
    112     '\xcf\x142B\xcfV\xd0\n\xbbPW\x80d\xd2\x0e\xf1\x1a\x04'
    113     '\x0b\xa8U=\x8f3\x85\xcd\x02\x03\x01\x00\x01'
    114 )
    115 # This is the matching private key.  Note that the public key is
    116 # a subset of this information should you need it for debugging.
    117 ENCRYPTION_PRIVATE_KEY = """
    118 -----BEGIN RSA PRIVATE KEY-----
    119 MIICXQIBAAKBgQDU43qCCzZEih1ZHd5sv60sDYvvbeO97zyVNJZDPJ5/Qu/oJmj7
    120 xFoOGTZDHddmiFw11R644I3EvNGzxNMpITfSexGJCfuN6LpSTKxJ8g8uSkKO1NzC
    121 gXY2ihU0vjj8qIR6SPBqhyjPFDJCz1bQCrtQV4Bk0g7xGgQLqFU9jzOFzQIDAQAB
    122 AoGBALfdR/9s44/KoZJIQ8Q0v8HeaU9+30U5jF9pLaYggtty2nTsR5u6d/TZPY42
    123 BcVeXBV6XbBa8NZMJelXQvCw6d3hrirtRgqo+R9n6Z5Ji9oKA9NR0ZD0d66OLgRz
    124 7U1w2wiM9KqfjRpRhuID1MrDF8R0mxORSFnlMeoHD74ncK6ZAkEA+NBV2OOigyU/
    125 CVWCTKmOpxUGb6bRZfvQRln4XlVUhSgZU0Acf0APl3Av1vUPyPjRIXRnMS5ZBDFK
    126 YoUqWH3ymwJBANsJhX3HHYXk7aDrmPKE7q25xR7Eu4C7XEdiG0SSl8PNAicU0APy
    127 zFs9GLhTgGCTZf/SCzH6ejEIiOC/RZeqW7cCQCapAF3F6O9lryi9H5TX17GAY9Kf
    128 YfPtr4vu2NeXfJ2AAIdd88+V3ZZTOSu2QjCg8KW5F3udzvkGy58JP+4mC7cCQBEU
    129 +gMoHyZNBzcwiHoJYe/MeBIBN7o/Yl/yx7ueTxWnDE7t8ZcNPWC0MBRX9sARXrgH
    130 snXQWe0vBDW61PuR/psCQQDthOoMBnuWamOEZrEJr+itK5+ZPlE+KpT3ladXui57
    131 zvz3CljmlLwyufahWaF+LzfohVAG5CLr4Zi/bv7j1lnJ
    132 -----END RSA PRIVATE KEY-----
    133 """
    134 
    135 
    136 def unicode2str(value):
    137     """
    138     Recurses through value, converting unicode to strings.
    139 
    140     The output of the json python decoder looks like a dictionary with
    141     unicode keys mapping to more unicode strings, and possibly
    142     dictionaries.  Convert those unicode strings to ASCII strings
    143     recursively with this function.
    144 
    145     @param value: dict or unicode.
    146     @returns value with unicode recursively replaced with string.
    147 
    148     """
    149     if isinstance(value, dict):
    150         ret = {}
    151         for k,v in value.items():
    152             ret[unicode2str(k)] = unicode2str(v)
    153         return ret
    154 
    155     if isinstance(value, unicode):
    156         return str(value)
    157 
    158     return value
    159 
    160 
    161 class network_DestinationVerification(test.test):
    162     """Tests that the destination verification logic in shill works.
    163 
    164     This logic allows us to verify that (for instance) we trust the
    165     credentials of a Chromekey.
    166 
    167     """
    168     version = 1
    169 
    170 
    171     @property
    172     def shim_path(self):
    173         """@return path to crypto-util shim."""
    174         lib_paths = ['lib', 'lib64']
    175         shim_path = '/usr/%s/shill/shims/crypto-util'
    176         for lib in lib_paths:
    177             path = shim_path % lib
    178             if os.path.exists(path):
    179                 return path
    180         raise error.TestFail('Unable to find crypto-util.')
    181 
    182 
    183     def _call_shim_with_args(self, args, protobuffer):
    184         """Calls the crypto_util shim with args and stdin as specified.
    185 
    186         Calls crypto shim with args for paramters, and the serialized form of
    187         protobuffer on stdin.  Asserts that the command completes successfully
    188         and returns the raw output bytestring.
    189 
    190         @param args: tuple of string arguments to the shim.
    191         @param protobuffer: python protocol buffer object.
    192         @return stdout of the shim call as string.
    193 
    194         """
    195         raw_input_bytes = protobuffer.SerializeToString()
    196         result  = utils.run(self.shim_path,
    197                             stderr_tee=utils.TEE_TO_LOGS,
    198                             stdin=raw_input_bytes,
    199                             verbose=True,
    200                             args=args,
    201                             timeout=10,
    202                             ignore_status=True)
    203         if result.exit_status:
    204             return None
    205         raw_output = result.stdout
    206         logging.debug('Got raw output: %s.',
    207                       ''.join([hex(ord(c)) for c in raw_output]))
    208         return raw_output
    209 
    210 
    211     def _test_verify(self, test_data, expect_failure=False):
    212         """Test that shim verify operation works correctly.
    213 
    214         Call into the shim to perform a verify operation, check that the call
    215         succeeds unless |expect_failure|.  |test_data| looks like the decoded
    216         json data we're given by the destination.
    217 
    218         @param test_data: dictionary of test data to use with the call.
    219         @param expect_failure: bool true if test_data should fail to verify.
    220 
    221         @raises TestFail when verification doesn't go as expected.
    222 
    223         """
    224         # See doc/manager-api.txt, but the format goes roughly:
    225         #     ssid,udn,bssid,key,nonce
    226         sign_bundle = test_data['sign']
    227         unsigned_data = '%s,%s,%s,%s,%s' % (test_data['name'],
    228                                             test_data['ssdp_udn'],
    229                                             test_data['hotspot_bssid'],
    230                                             test_data['public_key'],
    231                                             sign_bundle['nonce'])
    232         message = crypto_util_pb2.VerifyCredentialsMessage()
    233         message.certificate = sign_bundle['certificate']
    234         message.signed_data = base64.b64decode(sign_bundle['signed_data'])
    235         message.unsigned_data = unsigned_data
    236         message.mac_address = test_data['hotspot_bssid']
    237         output = self._call_shim_with_args(('verify',), message)
    238         if expect_failure:
    239             if output is None:
    240                 # Expected a failure, and got it.  We're done here.
    241                 return
    242             raise error.TestFail('Expected verification to fail, but it '
    243                                  'succeeded.')
    244 
    245         if not output:
    246             raise error.TestFail('Verification failed unexpectedly.')
    247 
    248         response = crypto_util_pb2.VerifyCredentialsResponse()
    249         response.ParseFromString(output)
    250         if response.ret != crypto_util_pb2.OK:
    251             raise error.TestFail('Expected verification success, '
    252                                  'but got: %d.' % response.ret)
    253 
    254 
    255     def _test_encrypt(self, public_key, data_to_encrypt, expect_failure=False):
    256         """Test that shim encrypt operation works correctly.
    257 
    258         Call into the shim to perform an encrypt operation.
    259         Raise a test error if the call fails, unless |expect_failure|.
    260 
    261         @param public_key: string containing RSAPublicKey format RSA key.
    262         @param data_to_encrypt: string data to encrypt.
    263         @param expect_failure: bool true if encrypt should fail.
    264 
    265         """
    266         message = crypto_util_pb2.EncryptDataMessage()
    267         message.public_key = public_key
    268         message.data = data_to_encrypt
    269         output = self._call_shim_with_args(('encrypt',), message)
    270         if expect_failure:
    271             if output is None:
    272                 # Expected a failure, and got it.  We're done here.
    273                 return
    274             raise error.TestFail('Expected encryption to fail, '
    275                                  'but it did not.')
    276 
    277         if not output:
    278             raise error.TestFail('Encryption failed unexpectedly.')
    279 
    280         response = crypto_util_pb2.EncryptDataResponse()
    281         response.ParseFromString(output)
    282         if response.ret != crypto_util_pb2.OK:
    283             raise error.TestFail('Data encryption failed.')
    284 
    285         logging.debug('Decrypting %d bytes of encrypted data to confirm match.',
    286                       len(response.encrypted_data))
    287         try:
    288             private_key = tempfile.NamedTemporaryFile()
    289             encrypted_data = tempfile.NamedTemporaryFile()
    290             private_key.write(ENCRYPTION_PRIVATE_KEY)
    291             private_key.flush()
    292             encrypted_data.write(response.encrypted_data)
    293             encrypted_data.flush()
    294             result = utils.run('openssl rsautl -decrypt -inkey %s -in %s' %
    295                                        (private_key.name, encrypted_data.name),
    296                                stdin=response.encrypted_data,
    297                                stderr_tee=utils.TEE_TO_LOGS,
    298                                verbose=True,
    299                                ignore_status=True)
    300             if result.exit_status:
    301                 if data_to_encrypt == '':
    302                     # Due to an open bug in OpenSSL, rsautl doesn't handle this
    303                     # case correctly.  For now, just pass and assume that
    304                     # we're doing this correctly.
    305                     # http://rt.openssl.org/Ticket/Display.html?id=2018
    306                     return
    307                 raise error.TestFail('Failed to decrypt shim output.')
    308 
    309             if result.stdout != data_to_encrypt:
    310                 raise error.TestFail('Data encyption failed: '
    311                                      'expected: %s, but got: %s' %
    312                                      (data_to_encrypt, result.stdout))
    313 
    314         finally:
    315             private_key.close()
    316             encrypted_data.close()
    317 
    318 
    319     def run_once(self):
    320         """Body of the test."""
    321         logging.info('Checking basic encryption operation of the shim.')
    322         self._test_encrypt(ENCRYPTION_PUBLIC_KEY, 'disco boy')
    323 
    324         logging.info('Checking graceful fail for too much data to encrypt.')
    325         self._test_encrypt(ENCRYPTION_PUBLIC_KEY,
    326                            ''.join(['x' for i in range(500)]),
    327                             expect_failure=True)
    328 
    329         logging.info('Checking graceful fail for a bad key format.')
    330         self._test_encrypt('this will not parse in openssl',
    331                             'disco boy',
    332                             expect_failure=True)
    333 
    334         logging.info('Checking that we encrypt the empty string correctly.')
    335         self._test_encrypt(ENCRYPTION_PUBLIC_KEY, '')
    336 
    337         logging.info('Checking basic verification operation.')
    338         test_data = unicode2str(json.loads(TEST_DATA1))
    339         self._test_verify(test_data)
    340 
    341         logging.info('Checking bad nonce in unsigned_data.')
    342         test_data = unicode2str(json.loads(TEST_DATA1))
    343         test_data['sign']['nonce'] = 'does not match'
    344         self._test_verify(test_data, expect_failure=True)
    345 
    346         logging.info('Checking for graceful fail for invalid '
    347                      'certificate format')
    348         test_data = unicode2str(json.loads(TEST_DATA1))
    349         test_data['sign']['certificate'] = 'not a certificate'
    350         self._test_verify(test_data, expect_failure=True)
    351 
    352         logging.info('Verification fails when the certificate is signed, but '
    353                      'subject is malformed.')
    354         test_data = unicode2str(json.loads(TEST_DATA2))
    355         self._test_verify(test_data, expect_failure=True)
    356 
    357         logging.info('Verification should succeed on third set of data.')
    358         test_data = unicode2str(json.loads(TEST_DATA3))
    359         self._test_verify(test_data)
    360 
    361         logging.info('Test completed successfully.')
    362