skip to main content
10.1145/3213846.3213851acmconferencesArticle/Chapter ViewAbstractPublication PagesisstaConference Proceedingsconference-collections

Eliminating timing side-channel leaks using program repair

Published:12 July 2018Publication History

ABSTRACT

We propose a method, based on program analysis and transformation, for eliminating timing side channels in software code that implements security-critical applications. Our method takes as input the original program together with a list of secret variables (e.g., cryptographic keys, security tokens, or passwords) and returns the transformed program as output. The transformed program is guaranteed to be functionally equivalent to the original program and free of both instruction- and cache-timing side channels. Specifically, we ensure that the number of CPU cycles taken to execute any path is independent of the secret data, and the cache behavior of memory accesses, in terms of hits and misses, is independent of the secret data. We have implemented our method in LLVM and validated its effectiveness on a large set of applications, which are cryptographic libraries with 19,708 lines of C/C++ code in total. Our experiments show the method is both scalable for real applications and effective in eliminating timing side channels.

References

  1. Botan: Crypto and TLS for C++11. https://github.com/randombit/botan/.Google ScholarGoogle Scholar
  2. Fair Evaluation of Lightweight Cryptographic Systems. https://www.cryptolux. org/index.php/FELICS.Google ScholarGoogle Scholar
  3. Libgcrypt. https://gnupg.org/software/libgcrypt/index.html.Google ScholarGoogle Scholar
  4. Libgcrypt. https://www.gnupg.org/software/libgcrypt/index.html.Google ScholarGoogle Scholar
  5. System for Unified Performance Evaluation Related to Cryptographic Operations and Primitives. https://bench.cr.yp.to/supercop.html.Google ScholarGoogle Scholar
  6. The LLVM Compiler Infrastructure. http://llvm.org/.Google ScholarGoogle Scholar
  7. Johan Agat. Transforming out timing leaks. In ACM SIGACT-SIGPLAN Symposium on Principles of Programming Languages, pages 40–53, 2000. Google ScholarGoogle ScholarDigital LibraryDigital Library
  8. Giovanni Agosta, Alessandro Barenghi, and Gerardo Pelosi. A code morphing methodology to automate power analysis countermeasures. In ACM/IEEE Design Automation Conference, pages 77–82, 2012. Google ScholarGoogle ScholarDigital LibraryDigital Library
  9. Nadhem J. AlFardan and Kenneth G. Paterson. Lucky thirteen: Breaking the TLS and DTLS record protocols. In IEEE Symposium on Security and Privacy, pages 526–540, 2013. Google ScholarGoogle ScholarDigital LibraryDigital Library
  10. Mário S. Alvim, Konstantinos Chatzikokolakis, Annabelle McIver, Carroll Morgan, Catuscia Palamidessi, and Geoffrey Smith. Additive and multiplicative notions of leakage, and their capacities. In IEEE Computer Security Foundations Symposium, pages 308–322, 2014. Google ScholarGoogle ScholarDigital LibraryDigital Library
  11. Timos Antonopoulos, Paul Gazzillo, Michael Hicks, Eric Koskinen, Tachio Terauchi, and Shiyi Wei. Decomposition instead of self-composition for proving the absence of timing channels. In ACM SIGPLAN Conference on Programming Language Design and Implementation, pages 362–375, 2017. Google ScholarGoogle ScholarDigital LibraryDigital Library
  12. Aslan Askarov, Danfeng Zhang, and Andrew C. Myers. Predictive black-box mitigation of timing channels. In ACM Conference on Computer and Communications Security, pages 297–307, 2010. Google ScholarGoogle ScholarDigital LibraryDigital Library
  13. Zelalem Birhanu Aweke and Todd M. Austin. Øzone: Efficient execution with zero timing leakage for modern microarchitectures. In IEEE International Symposium on Hardware Oriented Security and Trust, page 153, 2017.Google ScholarGoogle ScholarCross RefCross Ref
  14. Michael Backes and Boris Köpf. Formally bounding the side-channel leakage in unknown-message attacks. In European Symposium on Research in Computer Security, pages 517–532, 2008. Google ScholarGoogle ScholarDigital LibraryDigital Library
  15. George Balatsouras and Yannis Smaragdakis. Structure-sensitive points-to analysis for C and C++. In International Symposium on Static Analysis, pages 84–104, 2016.Google ScholarGoogle ScholarCross RefCross Ref
  16. Lucas Bang, Abdulbaki Aydin, Quoc-Sang Phan, Corina S. Pasareanu, and Tevfik Bultan. String analysis for side channels with segmented oracles. In ACM SIGSOFT Symposium on Foundations of Software Engineering, pages 193–204, 2016. Google ScholarGoogle ScholarDigital LibraryDigital Library
  17. Gilles Barthe, Tamara Rezk, and Martijn Warnier. Preventing timing leaks through transactional branching instructions. Electr. Notes Theor. Comput. Sci., 153(2):33– 55, 2006. Google ScholarGoogle ScholarDigital LibraryDigital Library
  18. Tiyash Basu and Sudipta Chattopadhyay. Testing cache side-channel leakage. In IEEE International Conference on Software Testing, Verification and Validation Workshops, pages 51–60, 2017.Google ScholarGoogle ScholarCross RefCross Ref
  19. Ali Galip Bayrak, Francesco Regazzoni, Philip Brisk, François-Xavier Standaert, and Paolo Ienne. A first step towards automatic application of power analysis countermeasures. In ACM/IEEE Design Automation Conference, pages 230–235, 2011. Google ScholarGoogle ScholarDigital LibraryDigital Library
  20. Eli Biham and Adi Shamir. Differential fault analysis of secret key cryptosystems. In International Cryptology Conference, pages 513–525, 1997. Google ScholarGoogle ScholarDigital LibraryDigital Library
  21. Nathan L. Binkert, Bradford M. Beckmann, Gabriel Black, Steven K. Reinhardt, Ali G. Saidi, Arkaprava Basu, Joel Hestness, Derek Hower, Tushar Krishna, Somayeh Sardashti, Rathijit Sen, Korey Sewell, Muhammad Shoaib Bin Altaf, Nilay Vaish, Mark D. Hill, and David A. Wood. The gem5 simulator. SIGARCH Computer Architecture News, 39(2):1–7, 2011. Google ScholarGoogle ScholarDigital LibraryDigital Library
  22. Andrew Bortz and Dan Boneh. Exposing private information by timing web applications. In International Conference on World Wide Web, pages 621–628, 2007. Google ScholarGoogle ScholarDigital LibraryDigital Library
  23. Benjamin A. Braun, Suman Jana, and Dan Boneh. Robust and efficient elimination of cache and timing side channels. CoRR, abs/1506.00189, 2015.Google ScholarGoogle Scholar
  24. David Brumley and Dan Boneh. Remote timing attacks are practical. Computer Networks, 48(5):701–716, 2005. Google ScholarGoogle ScholarCross RefCross Ref
  25. Sudipta Chattopadhyay. Directed automated memory performance testing. In International Conference on Tools and Algorithms for Construction and Analysis of Systems, pages 38–55, 2017. Google ScholarGoogle ScholarDigital LibraryDigital Library
  26. Jia Chen, Yu Feng, and Isil Dillig. Precise detection of side-channel vulnerabilities using quantitative cartesian hoare logic. In Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security, pages 875–890, 2017. Google ScholarGoogle ScholarDigital LibraryDigital Library
  27. Duc-Hiep Chu, Joxan Jaffar, and Rasool Maghareh. Precise cache timing analysis via symbolic execution. In IEEE Real-Time and Embedded Technology and Applications Symposium, pages 293–304, 2016.Google ScholarGoogle ScholarCross RefCross Ref
  28. David Cock, Qian Ge, Toby C. Murray, and Gernot Heiser. The last mile: An empirical study of timing channels on seL4. In ACM SIGSAC Conference on Computer and Communications Security, pages 570–581, 2014. Google ScholarGoogle ScholarDigital LibraryDigital Library
  29. Bart Coppens, Ingrid Verbauwhede, Koen De Bosschere, and Bjorn De Sutter. Practical mitigations for timing-based side-channel attacks on modern x86 processors. In IEEE Symposium on Security and Privacy, pages 45–60, 2009. Google ScholarGoogle ScholarDigital LibraryDigital Library
  30. Patrick Cousot and Radhia Cousot. Abstract interpretation: A unified lattice model for static analysis of programs by construction or approximation of fixpoints. In ACM SIGACT-SIGPLAN Symposium on Principles of Programming Languages, pages 238–252, 1977. Google ScholarGoogle ScholarDigital LibraryDigital Library
  31. Stephen Crane, Andrei Homescu, Stefan Brunthaler, Per Larsen, and Michael Franz. Thwarting cache side-channel attacks through dynamic software diversity. In Annual Network and Distributed System Security Symposium, 2015.Google ScholarGoogle ScholarCross RefCross Ref
  32. Matthew Dellinger, Piyush Garyali, and Binoy Ravindran. Chronos linux: a besteffort real-time multiprocessor linux kernel. In ACM/IEEE Design Automation Conference, pages 474–479, 2011. Google ScholarGoogle ScholarDigital LibraryDigital Library
  33. Daniel Dinu, Yann Le Corre, Dmitry Khovratovich, Leo Perrin, Johann Grobschadl, and Alex Biryukov. Triathlon of lightweight block ciphers for the internet of things. Cryptology ePrint Archive, Report 2015/209, 2015.Google ScholarGoogle Scholar
  34. Goran Doychev, Dominik Feld, Boris Köpf, Laurent Mauborgne, and Jan Reineke. CacheAudit: A tool for the static analysis of cache side channels. In USENIX Security, pages 431–446, 2013. Google ScholarGoogle ScholarDigital LibraryDigital Library
  35. Goran Doychev, Boris Köpf, Laurent Mauborgne, and Jan Reineke. Cacheaudit: A tool for the static analysis of cache side channels. ACM Trans. Inf. Syst. Secur., 18(1):4:1–4:32, 2015. Google ScholarGoogle ScholarDigital LibraryDigital Library
  36. Hassan Eldib and Chao Wang. Synthesis of masking countermeasures against side channel attacks. In International Conference on Computer Aided Verification, pages 114–130, 2014. Google ScholarGoogle ScholarDigital LibraryDigital Library
  37. Hassan Eldib, Chao Wang, and Patrick Schaumont. SMT-based verification of software countermeasures against side-channel attacks. In International Conference on Tools and Algorithms for Construction and Analysis of Systems, pages 62–77, 2014.Google ScholarGoogle ScholarCross RefCross Ref
  38. Hassan Eldib, Chao Wang, Mostafa Taha, and Patrick Schaumont. QMS: Evaluating the side-channel resistance of masked software from source code. In ACM/IEEE Design Automation Conference, pages 209:1–6, 2014. Google ScholarGoogle ScholarDigital LibraryDigital Library
  39. Hassan Eldib, Meng Wu, and Chao Wang. Synthesis of fault-attack countermeasures for cryptographic circuits. In International Conference on Computer Aided Verification, pages 343–363, 2016.Google ScholarGoogle ScholarCross RefCross Ref
  40. Oded Goldreich and Rafail Ostrovsky. Software protection and simulation on oblivious rams. Journal of the ACM, 43(3):431–473, 1996. Google ScholarGoogle ScholarDigital LibraryDigital Library
  41. Philipp Grabher, Johann Großschädl, and Dan Page. Cryptographic side-channels from low-power cache memory. In International Conference on Cryptography and Coding, pages 170–184, 2007. Google ScholarGoogle ScholarDigital LibraryDigital Library
  42. David Gullasch, Endre Bangerter, and Stephan Krenn. Cache games–bringing access-based cache attacks on aes to practice. In IEEE Symposium on Security and Privacy, pages 490–505, 2011. Google ScholarGoogle ScholarDigital LibraryDigital Library
  43. Shengjian Guo, Markus Kusano, and Chao Wang. Conc-iSE: Incremental symbolic execution of concurrent software. In IEEE/ACM International Conference On Automated Software Engineering, 2016. Google ScholarGoogle ScholarDigital LibraryDigital Library
  44. Shengjian Guo, Markus Kusano, Chao Wang, Zijiang Yang, and Aarti Gupta. Assertion guided symbolic execution of multithreaded programs. In ACM SIGSOFT Symposium on Foundations of Software Engineering, pages 854–865, 2015. Google ScholarGoogle ScholarDigital LibraryDigital Library
  45. Shengjian Guo, Meng Wu, and Chao Wang. Symbolic execution of programmable logic controller code. In ACM SIGSOFT Symposium on Foundations of Software Engineering, pages 326–336, 2017. Google ScholarGoogle ScholarDigital LibraryDigital Library
  46. Shengjian Guo, Meng Wu, and Chao Wang. Adversarial symbolic execution for detecting concurrency-related cache timing leaks. 2018.Google ScholarGoogle Scholar
  47. Daniel Hedin and David Sands. Timing aware information flow security for a javacard-like bytecode. Electr. Notes Theor. Comput. Sci., 141(1):163–182, 2005. Google ScholarGoogle ScholarDigital LibraryDigital Library
  48. Wei-Ming Hu. Reducing timing channels with fuzzy time. In IEEE Symposium on Security and Privacy, pages 8–20, 1991.Google ScholarGoogle ScholarCross RefCross Ref
  49. Zhen Hang Jiang, Yunsi Fei, and David R. Kaeli. A complete key recovery timing attack on a GPU. In IEEE International Symposium on High Performance Computer Architecture, pages 394–405, 2016.Google ScholarGoogle ScholarCross RefCross Ref
  50. Paul Kocher, Daniel Genkin, Daniel Gruss, Werner Haas, Mike Hamburg, Moritz Lipp, Stefan Mangard, Thomas Prescher, Michael Schwarz, and Yuval Yarom. Spectre attacks: Exploiting speculative execution. ArXiv e-prints, January 2018.Google ScholarGoogle Scholar
  51. Paul C Kocher. Timing attacks on implementations of Diffie-Hellman, RSA, DSS, and other systems. In Annual International Cryptology Conference, pages 104–113. Springer, 1996. Google ScholarGoogle ScholarDigital LibraryDigital Library
  52. Paul C. Kocher, Joshua Jaffe, and Benjamin Jun. Differential power analysis. In International Cryptology Conference, pages 388–397, 1999. Google ScholarGoogle ScholarDigital LibraryDigital Library
  53. Boris Köpf and Markus Dürmuth. A provably secure and efficient countermeasure against timing attacks. In IEEE Computer Security Foundations Symposium, pages 324–335, 2009. Google ScholarGoogle ScholarDigital LibraryDigital Library
  54. Boris Köpf and Heiko Mantel. Transformational typing and unification for automatically correcting insecure programs. Int. J. Inf. Sec., 6(2-3):107–131, 2007. Google ScholarGoogle ScholarCross RefCross Ref
  55. Boris Köpf, Laurent Mauborgne, and Martín Ochoa. Automatic quantification of cache side-channels. In International Conference on Computer Aided Verification, pages 564–580, 2012. Google ScholarGoogle ScholarDigital LibraryDigital Library
  56. Boris Köpf and Geoffrey Smith. Vulnerability bounds and leakage resilience of blinded cryptography under timing attacks. In IEEE Computer Security Foundations Symposium, pages 44–56, 2010. Google ScholarGoogle ScholarDigital LibraryDigital Library
  57. Moritz Lipp, Michael Schwarz, Daniel Gruss, Thomas Prescher, Werner Haas, Stefan Mangard, Paul Kocher, Daniel Genkin, Yuval Yarom, and Mike Hamburg. Meltdown. ArXiv e-prints, January 2018.Google ScholarGoogle Scholar
  58. ISSTA’18, July 16–21, 2018, Amsterdam, Netherlands Meng Wu, Shengjian Guo, Patrick Schaumont, and Chao WangGoogle ScholarGoogle Scholar
  59. Chang Liu, Austin Harris, Martin Maas, Michael Hicks, Mohit Tiwari, and Elaine Shi. Ghostrider: A hardware-software system for memory trace oblivious computation. ACM SIGARCH Computer Architecture News, 43(1):87–101, 2015. Google ScholarGoogle ScholarDigital LibraryDigital Library
  60. Fangfei Liu, Qian Ge, Yuval Yarom, Frank Mckeen, Carlos Rozas, Gernot Heiser, and Ruby B Lee. Catalyst: Defeating last-level cache side channel attacks in cloud computing. In IEEE International Symposium On High Performance Computer Architecture, pages 406–418, 2016.Google ScholarGoogle ScholarCross RefCross Ref
  61. Stefan Mangard, Elisabeth Oswald, and Thomas Popp. Power Analysis Attacks - Revealing the Secrets of Smart Cards. Springer, 2007. Google ScholarGoogle ScholarDigital LibraryDigital Library
  62. Heiko Mantel and Artem Starostin. Transforming out timing leaks, more or less. In European Symposium on Research in Computer Security, pages 447–467, 2015. Google ScholarGoogle ScholarDigital LibraryDigital Library
  63. Jonathan K. Millen. Covert channel capacity. In IEEE Symposium on Security and Privacy, pages 60–66, 1987.Google ScholarGoogle ScholarCross RefCross Ref
  64. David Molnar, Matt Piotrowski, David Schultz, and David Wagner. The program counter security model: Automatic detection and removal of control-flow side channel attacks. In International Conference on Information Security and Cryptology, pages 156–168. Springer, 2005. Google ScholarGoogle ScholarDigital LibraryDigital Library
  65. Andrew Moss, Elisabeth Oswald, Dan Page, and Michael Tunstall. Compiler assisted masking. In International Conference on Cryptographic Hardware and Embedded Systems, pages 58–75, 2012. Google ScholarGoogle ScholarDigital LibraryDigital Library
  66. Keaton Mowery, Sriram Keelveedhi, and Hovav Shacham. Are aes x86 cache timing attacks still feasible? In ACM Workshop on Cloud computing security, pages 19–24, 2012. Google ScholarGoogle ScholarDigital LibraryDigital Library
  67. Yoshitaka Nagami, Daisuke Miyamoto, Hiroaki Hazeyama, and Youki Kadobayashi. An independent evaluation of web timing attack and its countermeasure. In International Conference on Availability, Reliability and Security, pages 1319–1324, 2008. Google ScholarGoogle ScholarDigital LibraryDigital Library
  68. Dag Arne Osvik, Adi Shamir, and Eran Tromer. Cache attacks and countermeasures: The case of AES. In Topics in Cryptology - CT-RSA 2006, The Cryptographers’ Track at the RSA Conference 2006, San Jose, CA, USA, February 13-17, 2006, Proceedings, pages 1–20, 2006. Google ScholarGoogle ScholarDigital LibraryDigital Library
  69. Dan Page. Partitioned cache architecture as a side-channel defence mechanism.Google ScholarGoogle Scholar
  70. David J. Pearce, Paul H. J. Kelly, and Chris Hankin. Efficient field-sensitive pointer analysis for C. In ACM SIGPLAN-SIGSOFT Workshop on Program Analysis For Software Tools and Engineering, 2004. Google ScholarGoogle ScholarDigital LibraryDigital Library
  71. Quoc-Sang Phan, Lucas Bang, Corina S. Pasareanu, Pasquale Malacaria, and Tevfik Bultan. Synthesis of adaptive side-channel attacks. In IEEE Computer Security Foundations Symposium, pages 328–342, 2017.Google ScholarGoogle ScholarCross RefCross Ref
  72. Alessandra Di Pierro, Chris Hankin, and Herbert Wiklicky. Probabilistic timing covert channels: to close or not to close? Int. J. Inf. Sec., 10(2):83–106, 2011. Google ScholarGoogle ScholarDigital LibraryDigital Library
  73. Ashay Rane, Calvin Lin, and Mohit Tiwari. Raccoon: closing digital side-channels through obfuscated execution. In USENIX Security Symposium, pages 431–446, 2015. Google ScholarGoogle ScholarDigital LibraryDigital Library
  74. Sebastian Schinzel. An efficient mitigation method for timing side channels on the web. In International Workshop on Constructive Side-Channel Analysis and Secure Design, 2011.Google ScholarGoogle Scholar
  75. Bruce Schneier. Applied cryptography: protocols, algorithms, and source code in C. John Wiley & Sons, 2007.Google ScholarGoogle Scholar
  76. Claude E. Shannon. A mathematical theory of communication. The Bell System Technical Journal, 27:379–423, 1948.Google ScholarGoogle ScholarCross RefCross Ref
  77. Geoffrey Smith. On the foundations of quantitative information flow. In International Conference on the Foundations of Software Science and Computational Structures, pages 288–302, 2009.Google ScholarGoogle ScholarCross RefCross Ref
  78. Marcelo Sousa and Isil Dillig. Cartesian hoare logic for verifying k-safety properties. In ACM SIGPLAN Conference on Programming Language Design and Implementation, pages 57–69, 2016. Google ScholarGoogle ScholarDigital LibraryDigital Library
  79. Raphael Spreitzer and Thomas Plos. On the applicability of time-driven cache attacks on mobile devices. In International Conference on Network and System Security, pages 656–662. Springer, 2013.Google ScholarGoogle Scholar
  80. Emil Stefanov, Marten Van Dijk, Elaine Shi, Christopher Fletcher, Ling Ren, Xiangyao Yu, and Srinivas Devadas. Path ORAM: an extremely simple oblivious RAM protocol. In ACM SIGSAC Conference on Computer & Communications Security, pages 299–310, 2013. Google ScholarGoogle ScholarDigital LibraryDigital Library
  81. Valentin Touzeau, Claire Maïza, David Monniaux, and Jan Reineke. Ascertaining uncertainty for efficient exact cache analysis. In International Conference on Computer Aided Verification, pages 22–40, 2017.Google ScholarGoogle ScholarCross RefCross Ref
  82. Bhanu C Vattikonda, Sambit Das, and Hovav Shacham. Eliminating fine grained timers in xen. In ACM workshop on Cloud computing security, pages 41–46, 2011. Google ScholarGoogle ScholarDigital LibraryDigital Library
  83. Chao Wang and Patrick Schaumont. Security by compilation: an automated approach to comprehensive side-channel resistance. ACM SIGLOG News, 4(2):76– 89, 2017. Google ScholarGoogle ScholarDigital LibraryDigital Library
  84. Shuai Wang, Pei Wang, Xiao Liu, Danfeng Zhang, and Dinghao Wu. CacheD: Identifying cache-based timing channels in production software. In USENIX Security Symposium, pages 235–252. USENIX Association, 2017. Google ScholarGoogle ScholarDigital LibraryDigital Library
  85. Zhenghong Wang and Ruby B. Lee. New cache designs for thwarting software cache-based side channel attacks. In International Symposium on Computer Architecture, pages 494–505, 2007. Google ScholarGoogle ScholarDigital LibraryDigital Library
  86. Yuval Yarom and Katrina Falkner. FLUSH+RELOAD: A high resolution, low noise, L3 cache side-channel attack. In USENIX Security Symposium, pages 719–732, 2014. Google ScholarGoogle ScholarDigital LibraryDigital Library
  87. Danfeng Zhang, Aslan Askarov, and Andrew C Myers. Language-based control and mitigation of timing channels. In ACM SIGACT-SIGPLAN Symposium on Principles of Programming Languages, pages 99–110, 2012. Google ScholarGoogle ScholarDigital LibraryDigital Library
  88. Jun Zhang, Pengfei Gao, Fu Song, and Chao Wang. SCInfer: Refinement-based verification of software countermeasures against side-channel attacks. In International Conference on Computer Aided Verification, 2018.Google ScholarGoogle ScholarCross RefCross Ref

Index Terms

  1. Eliminating timing side-channel leaks using program repair

        Recommendations

        Comments

        Login options

        Check if you have access through your login credentials or your institution to get full access on this article.

        Sign in
        • Published in

          cover image ACM Conferences
          ISSTA 2018: Proceedings of the 27th ACM SIGSOFT International Symposium on Software Testing and Analysis
          July 2018
          379 pages
          ISBN:9781450356992
          DOI:10.1145/3213846
          • General Chair:
          • Frank Tip,
          • Program Chair:
          • Eric Bodden

          Copyright © 2018 ACM

          Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. Copyrights for components of this work owned by others than ACM must be honored. Abstracting with credit is permitted. To copy otherwise, or republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. Request permissions from [email protected]

          Publisher

          Association for Computing Machinery

          New York, NY, United States

          Publication History

          • Published: 12 July 2018

          Permissions

          Request permissions about this article.

          Request Permissions

          Check for updates

          Qualifiers

          • research-article

          Acceptance Rates

          Overall Acceptance Rate58of213submissions,27%

          Upcoming Conference

          ISSTA '24

        PDF Format

        View or Download as a PDF file.

        PDF

        eReader

        View online with eReader.

        eReader