1#!/usr/bin/env python 2 3# Copyright (C) 2016 g10 Code GmbH 4# 5# This file is part of GPGME. 6# 7# GPGME is free software; you can redistribute it and/or modify it 8# under the terms of the GNU General Public License as published by 9# the Free Software Foundation; either version 2 of the License, or 10# (at your option) any later version. 11# 12# GPGME is distributed in the hope that it will be useful, but WITHOUT 13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15# Public License for more details. 16# 17# You should have received a copy of the GNU Lesser General Public 18# License along with this program; if not, see <https://www.gnu.org/licenses/>. 19 20from __future__ import absolute_import, print_function, unicode_literals 21 22import os 23import platform 24import gpg 25import support 26_ = support # to appease pyflakes. 27 28del absolute_import, print_function, unicode_literals 29 30oops = None 31c = gpg.Context() 32c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) 33 34source = gpg.Data("Hallo Leute\n") 35sink = gpg.Data() 36 37# Valid passphrases, both as string and bytes. 38for passphrase in ('foo', b'foo'): 39 40 def passphrase_cb(hint, desc, prev_bad, hook=None): 41 assert hook == passphrase 42 return hook 43 44 c.set_passphrase_cb(passphrase_cb, passphrase) 45 c.op_encrypt([], 0, source, sink) 46 47 48# Returning an invalid type. 49def passphrase_cb(hint, desc, prev_bad, hook=None): 50 return 0 51 52 53c.set_passphrase_cb(passphrase_cb, None) 54try: 55 c.op_encrypt([], 0, source, sink) 56except Exception as e: 57 assert type(e) == TypeError 58 assert str(e) == "expected str or bytes from passphrase callback, got int" 59else: 60 assert False, "Expected an error, got none" 61 62# Raising an exception inside callback. 63myException = Exception() 64 65 66def passphrase_cb(hint, desc, prev_bad, hook=None): 67 raise myException 68 69 70c.set_passphrase_cb(passphrase_cb, None) 71try: 72 c.op_encrypt([], 0, source, sink) 73except Exception as e: 74 assert e == myException 75else: 76 assert False, "Expected an error, got none" 77 78 79# Wrong kind of callback function. 80def bad_passphrase_cb(): 81 pass 82 83 84c.set_passphrase_cb(bad_passphrase_cb, None) 85try: 86 c.op_encrypt([], 0, source, sink) 87except Exception as e: 88 assert type(e) == TypeError 89else: 90 assert False, "Expected an error, got none" 91 92# Test the progress callback. 93parms = """<GnupgKeyParms format="internal"> 94Key-Type: RSA 95Key-Length: 1024 96Name-Real: Joe Tester 97Name-Comment: with stupid passphrase 98Name-Email: joe+gpg@example.org 99Passphrase: Crypt0R0cks 100Expire-Date: 2099-12-31 101</GnupgKeyParms> 102""" 103 104prams = """<GnupgKeyParms format="internal"> 105Key-Type: RSA 106Key-Length: 1024 107Name-Real: Joe Tester 108Name-Comment: with stupid passphrase 109Name-Email: joe+gpg@example.org 110Passphrase: Crypt0R0cks 111Expire-Date: 2037-12-31 112</GnupgKeyParms> 113""" 114 115messages = [] 116 117 118def progress_cb(what, typ, current, total, hook=None): 119 assert hook == messages 120 messages.append( 121 "PROGRESS UPDATE: what = {}, type = {}, current = {}, total = {}" 122 .format(what, typ, current, total)) 123 124 125c = gpg.Context() 126c.set_progress_cb(progress_cb, messages) 127try: 128 c.op_genkey(parms, None, None) 129except Exception as oops: 130 c.op_genkey(prams, None, None) 131assert len(messages) > 0 132 133 134# Test exception handling. 135def progress_cb(what, typ, current, total, hook=None): 136 raise myException 137 138 139c = gpg.Context() 140c.set_progress_cb(progress_cb, None) 141try: 142 try: 143 c.op_genkey(parms, None, None) 144 except Exception as oops: 145 c.op_genkey(prams, None, None) 146except Exception as e: 147 assert e == myException 148else: 149 assert False, "Expected an error, got none" 150 151# Test the edit callback. 152c = gpg.Context() 153c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) 154c.set_passphrase_cb(lambda *args: "abc") 155sink = gpg.Data() 156alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) 157 158cookie = object() 159edit_cb_called = False 160 161def oops_check(): 162 if oops is not None and platform.architecture()[0] != "64bit": 163 y2k38_msg = "System appears to be 32-bit and vulnerable to EOL in 2038." 164 elif oops is not None and platform.architecture()[0] == "64bit": 165 y2k38_msg = "System appears to be 64-bit, but may use 32-bit time." 166 else: 167 y2k38_msg = "System is 64-bit and/or not susceptible to 2038 EOL." 168 return y2k38_msg 169 170 171def edit_cb(status, args, hook): 172 global edit_cb_called 173 edit_cb_called = True 174 assert hook == cookie 175 return "quit" if args == "keyedit.prompt" else None 176 177 178c.op_edit(alpha, edit_cb, cookie, sink) 179assert edit_cb_called 180 181# Test exceptions. 182c = gpg.Context() 183c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) 184c.set_passphrase_cb(lambda *args: "abc") 185sink = gpg.Data() 186 187 188def edit_cb(status, args): 189 raise myException 190 191 192try: 193 c.op_edit(alpha, edit_cb, None, sink) 194except Exception as e: 195 assert e == myException 196else: 197 assert False, "Expected an error, got none" 198 199# Test the status callback. 200source = gpg.Data("Hallo Leute\n") 201sink = gpg.Data() 202 203status_cb_called = False 204 205 206def status_cb(keyword, args, hook=None): 207 global status_cb_called 208 status_cb_called = True 209 assert hook == cookie 210 211 212c = gpg.Context() 213c.set_status_cb(status_cb, cookie) 214c.set_ctx_flag("full-status", "1") 215c.op_encrypt([alpha], gpg.constants.ENCRYPT_ALWAYS_TRUST, source, sink) 216assert status_cb_called 217 218# Test exceptions. 219source = gpg.Data("Hallo Leute\n") 220sink = gpg.Data() 221 222 223def status_cb(keyword, args): 224 raise myException 225 226 227c = gpg.Context() 228c.set_status_cb(status_cb, None) 229c.set_ctx_flag("full-status", "1") 230try: 231 c.op_encrypt([alpha], gpg.constants.ENCRYPT_ALWAYS_TRUST, source, sink) 232except Exception as e: 233 assert e == myException 234else: 235 assert False, "Expected an error, got none" 236 237 238# Test the data callbacks. 239def read_cb(amount, hook=None): 240 assert hook == cookie 241 return 0 242 243 244def release_cb(hook=None): 245 assert hook == cookie 246 247 248data = gpg.Data(cbs=(read_cb, None, None, release_cb, cookie)) 249try: 250 data.read() 251except Exception as e: 252 assert type(e) == TypeError 253else: 254 assert False, "Expected an error, got none" 255 256 257def read_cb(amount): 258 raise myException 259 260 261data = gpg.Data(cbs=(read_cb, None, None, lambda: None)) 262try: 263 data.read() 264except Exception as e: 265 assert e == myException 266else: 267 assert False, "Expected an error, got none" 268 269 270def write_cb(what, hook=None): 271 assert hook == cookie 272 return "wrong type" 273 274 275data = gpg.Data(cbs=(None, write_cb, None, release_cb, cookie)) 276try: 277 data.write(b'stuff') 278except Exception as e: 279 assert type(e) == TypeError 280else: 281 assert False, "Expected an error, got none" 282 283 284def write_cb(what): 285 raise myException 286 287 288data = gpg.Data(cbs=(None, write_cb, None, lambda: None)) 289try: 290 data.write(b'stuff') 291except Exception as e: 292 assert e == myException 293else: 294 assert False, "Expected an error, got none" 295 296 297def seek_cb(offset, whence, hook=None): 298 assert hook == cookie 299 return "wrong type" 300 301 302data = gpg.Data(cbs=(None, None, seek_cb, release_cb, cookie)) 303try: 304 data.seek(0, os.SEEK_SET) 305except Exception as e: 306 assert type(e) == TypeError 307else: 308 assert False, "Expected an error, got none" 309 310 311def seek_cb(offset, whence): 312 raise myException 313 314 315data = gpg.Data(cbs=(None, None, seek_cb, lambda: None)) 316try: 317 data.seek(0, os.SEEK_SET) 318except Exception as e: 319 assert e == myException 320else: 321 assert False, "Expected an error, got none" 322