TLS-ENFORCED ATTESTATION A Project Presented to the faculty of the Department of Computer Science California State University, Sacramento Submitted in partial satisfaction of the requirements for the degree of MASTER OF SCIENCE in Computer Science by Jonathan Buhacoff SPRING 2013 TLS-ENFORCED ATTESTATION A Project by Jonathan Buhacoff Approved by: __________________________________, Committee Chair Ted Krovetz, Ph.D. __________________________________, Second Reader Isaac Ghansah, Ph.D. ____________________________ Date ii Student: Jonathan Buhacoff I certify that this student has met the requirements for format contained in the University format manual, and that this project is suitable for shelving in the Library and credit is to be awarded for the project. __________________________, Graduate Coordinator Behnam Arad, Ph.D. Department of Computer Science iii ___________________ Date Abstract of TLS-ENFORCED ATTESTATION by Jonathan Buhacoff In client-server environments, clients need a mechanism to determine that a server can be trusted to provide services to the client. Transport layer security (TLS) provides a mechanism to trust the server’s identity by relying on certificates signed by trusted authorities. The client must implicitly trust that the server’s administrators maintain the server with trusted software, by installing security patches for example. Increasingly, clients will require more explicit assurances that a server can be trusted. It is possible to obtain such assurances in the form of an attestation by a Trusted Platform Module (TPM) on the server. The goal of this project is to develop a system that allows clients to determine that a server is running trusted software by leveraging the TLS protocol to enforce that a previously accepted attestation is still valid each time the client connects to the server. _______________________, Committee Chair Ted Krovez, Ph.D. _______________________ Date iv ACKNOWLEDGEMENTS I would like to extend very sincere and deep thanks to Professor and Department Chair Dr. Cui Zhang for her strong support and to Professors Dr. Ted Krovetz and Dr. Isaac Ghansah for supervising my work. I also thank Uttam Shetty and Raghuram Yeluri of Intel Corporation for their support and encouragement. I would also like to acknowledge Hal Finney of PGP Corporation and Kent Yoder of IBM, who have greatly contributed to my understanding of the subject through their published source code and numerous online postings. My wife Adrienne deserves special recognition for being the only person in the world who was still married to me at the time of this writing. The last 4 months were dedicated to this project, but all the rest of my days are dedicated to her. v TABLE OF CONTENTS Page Acknowledgements ..............................................................................................................v List of Figures .................................................................................................................... ix List of Abbreviations ...........................................................................................................x Chapters 1. INTRODUCTION ...........................................................................................................1 1.1 Background ........................................................................................................ 1 1.2 Software-based Security .................................................................................... 2 1.3 Trusted Computing Group ................................................................................. 4 1.4 Remote Attestation ............................................................................................. 7 1.5 Motivation .......................................................................................................... 9 1.6 Goal .................................................................................................................... 9 2. ARCHITECTURE .........................................................................................................11 2.1 Transport Layer Security ................................................................................. 11 2.2 Trusted Platform Module ................................................................................. 13 2.3 Trust ................................................................................................................. 16 2.4 Remote Attestation ........................................................................................... 17 2.5 Certificates ....................................................................................................... 18 2.6 Summary .......................................................................................................... 19 vi 3. IMPLEMENTATION ....................................................................................................21 3.1 Trust Authority................................................................................................. 21 3.2 Server ............................................................................................................... 23 3.3 Attestation ........................................................................................................ 27 3.4 Client ................................................................................................................ 30 3.5 Trust ................................................................................................................. 30 4. CONCLUSION ..............................................................................................................31 5. FUTURE WORK ...........................................................................................................33 5.1 Runtime Measurement ..................................................................................... 33 5.2 User-Space Measurement ................................................................................ 33 5.3 Global Knowledge ........................................................................................... 33 5.4 Client Attestation ............................................................................................. 33 5.5 PCR Contents as X.509v3 Extensions ............................................................. 34 5.6 Software Updates ............................................................................................. 34 5.7 Automation....................................................................................................... 35 5.8 Trust But Verify ............................................................................................... 35 Appendix A. Source Code .................................................................................................37 config.h .................................................................................................................. 38 config.c ................................................................................................................... 39 hex.h ....................................................................................................................... 41 hex.c ....................................................................................................................... 42 hex2bin.c ................................................................................................................ 46 vii showpcr.c ............................................................................................................... 47 extendpcr.c ............................................................................................................. 49 aikpublish.c ............................................................................................................ 51 aikchallenge.c ......................................................................................................... 57 aikrespond.c ........................................................................................................... 64 aikquote.c ............................................................................................................... 68 aikqverify.c ............................................................................................................ 73 create_tpm_key.c ................................................................................................... 76 Appendix B. Demonstration ..............................................................................................86 Client ...................................................................................................................... 86 Server ..................................................................................................................... 87 Appendix C. Security Tests ...............................................................................................88 Appendix D. OpenSSL ......................................................................................................91 Downloading OpenSSL ......................................................................................... 91 Installing OpenSSL ................................................................................................ 91 Appendix E. Trousers ........................................................................................................92 Downloading Trousers ........................................................................................... 92 Installing Trousers, TPM Tools, and TPM Engine for OpenSSL .......................... 92 Bibliography ......................................................................................................................94 viii LIST OF FIGURES Figures Page Figure 1. Client view of server using regular certificate authority ..................................... 2 Figure 2. Layers of abstraction ........................................................................................... 3 Figure 3. Extending a PCR ................................................................................................. 5 Figure 4. Illustration of a TPM Quote ................................................................................ 9 Figure 5. Client view of server using trust authority ........................................................ 10 Figure 6. Relationship of Client, Server, and Certificate Authority ................................. 12 Figure 7. Combining TLS and TPM ................................................................................. 13 Figure 8. Provisioning client and server certificates ......................................................... 18 Figure 9. Output of tpm_version ....................................................................................... 25 Figure 10. Content of pcr.manifest ................................................................................... 26 Figure 11. Example of failure to use sealed TPM private key.......................................... 26 Figure 12. Output of openssl rsa -in aik.pubkey -text -pubin -noout................................ 28 Figure 13. Output of aikqverify ........................................................................................ 30 ix LIST OF ABBREVIATIONS AIK Attestation Identity Key BIOS Basic Input/Output System CA Certificate Authority CSR Certificate Signing Request DAA Direct Anonymous Attestation DNS Domain Name System EK Endorsement Key IP Internet Protocol Nonce Number used only once NVRAM Non-Volatile Random Access Memory OS Operating System PCR Platform Configuration Register PEM Privacy Enhanced Mail RFC Request for Comments RSA Public key cryptography algorithm created by Rivest, Shamir, and Adleman SSL Secure Sockets Layer; SSLv2 for version 2; SSLv3 for version 3 TCG Trusted Computing Group TLS Transport Layer Security, successor of SSL TPM Trusted Platform Module x 1 Chapter 1 1. INTRODUCTION 1.1 Background In cloud computing and other client/server environments there is always a risk of attack to the server that would result in compromise of the client’s confidentiality and data integrity. Server environments range from software as a service, in which a provider is completely responsible for securing and monitoring its servers, to unmanaged dedicated hosting, in which a provider is only responsible for monitoring the network and maintaining the server hardware, and customers are completely responsible for the security of their servers [1]. The precautions implemented by server operators may include firewalls, anti-virus software, and intrusion detection systems. Typically, clients are not aware of the specific security measures implemented by server operators as shown in Figure 1. Clients implicitly trust that the servers they use are free of any malware, and that the software installed on the servers is suitable for accomplishing the client’s intended purpose. A client’s intended purpose may include enforcing security and policy constraints on data and processes in addition to providing confidentiality and data integrity. 2 Figure 1. Client view of server using regular certificate authority 1.2 Software-based Security Anti-virus software relies on being able to scan individual files on disk or in memory. Anti-virus software is typically signature-based, which means that files are scanned and compared against a database of known malware characteristics, or signatures, in order to identify possible malware. Another kind of anti-virus software described by [2] attempts to detect polymorphic viruses, which are viruses that deliberately change the way their code looks in order to avoid signature-based detection. Both types of anti-virus rely on being able to scan individual files which means they have two vulnerabilities: first, the list of files to scan can be manipulated so it does not include the malware; and second, the apparent contents of the files can be manipulated to return fake data for specific files in order to hide the presence of the malware. These vulnerabilities are always present in addition to any implementation-specific vulnerabilities of any security software. Host-based intrusion detection systems typically check the integrity of known system files [3] and may also check the behavior of running processes [4]. Such intrusiondetection systems have the same vulnerabilities as the anti-virus software, and in addition they also have a third vulnerability related to monitoring processes: malware that is able 3 to run at the operating system kernel level or as a device driver will have direct access to hardware and will be harder to track by a process monitor or by intercepting system calls. Modern computing systems are comprised of software that is stacked upon other software, each layer providing useful abstractions of the layer below it, and the layers extending down to the hardware drivers that abstract and control access to the computing hardware and peripherals as shown in Figure 2. A consequence of this architecture is that lower levels of software provide an environment for higher levels. In other words, higher levels of software can only perceive what lower levels make available. Because of this architecture, any security system that is rooted in software has the vulnerability that a compromise in lower levels of the software stack can manipulate the computing environment to avoid detection by a security system operating at a higher level in the software stack. Figure 2. Layers of abstraction It is not possible to mitigate this vulnerability by adding more levels of software, because there will always be a lowest level. If it’s possible to install or upgrade the software at the 4 lowest level then it is also possible to compromise it [5]. For this reason, clients who need assurances about the software running on the system cannot really trust a system with security rooted in software. The root of trust must therefore be in the hardware, where malware cannot compromise it due to hardware-enforced inability to overwrite its functions. 1.3 Trusted Computing Group An association of many software and hardware vendors known as the Trusted Computing Group (TCG) has created specifications for a Trusted Platform Module (TPM), which is a hardware component that is suitable for use as the root of trust in a security system [6] [7]. The TCG specifications provide the basis for a combined hardware and software solution that computer manufacturers can implement in order to enable software running at even the highest levels in the software stack to detect tampering with the firmware, boot loading code, operating system kernel, and any other trusted software at lower levels. Every TPM is able to internally perform encryption, decryption, and hashing. A TPM also contains a bank of 24 registers, each one with a capacity to store 20 bytes of data [8]. These are called Platform Configuration Registers (PCR) because they are used to store information about the computer system in which the TPM is installed. The PCRs are said to be volatile memory because they lose their contents when the power is reset. A TPM also contains some non-volatile memory called NVRAM that can be used to store important information across power cycles. A TPM has three key features that make it suitable to use as the root of trust for a computing system. 5 First, only the TPM is able to reset the contents of any PCR. During power-on, each PCR is initialized with 20 bytes of zero [9]. From that point on, any hardware or software external to the TPM can only extend the contents of a PCR, not reset it. When a PCR is extended, the 20 bytes are replaced with the result of a function of both its previous contents and the new data as shown in Figure 3. The function used is the Secure Hash Algorithm (SHA-1) which is a one-way function. This means that external hardware and software determines what data is extended into a PCR but cannot control what will be the PCR’s new contents. Figure 3. Extending a PCR Second, the TPM can provide a quote, which is a digitally signed report of the contents of all or selected PCRs [10]. The quote is signed by a private key that is created and used exclusively by the TPM internally and cannot be read by any hardware or software external to the TPM. The corresponding public key can therefore be used to determine that a quote was digitally signed by the TPM and not by anything else, especially 6 software. A quote is also called an attestation of the platform state, and the private key is also called an Attestation Identity Key (AIK). The public key must sent securely to challengers as described in the next section, Remote Attestation. Third, each TPM contains an Endorsement Key (EK) that can be used to authenticate the TPM itself, so that software relying on TPM quotes can trust that the corresponding AIK exists in a real hardware TPM and not in any other software, such as a TPM emulator [11]. When the TPM in a server is enabled, these three key features are combined to create a root of trust in the following way: Starting at boot, any software that executes is first measured and its measurement is extended into a PCR. Measuring software means loading its binary code and using it as an input into a one-way function in order to produce a short summary of the code, known as a digest. For example, before the CPU starts executing the BIOS, it first measures the BIOS and then extends a PCR with the measurement [12]. The BIOS then needs to load some drivers and the operating system kernel, but before doing so it first measures each one and extends a PCR with the measurements. At each step, the contents of the PCR bank are modified but they always reflect the entire history of extensions since power on. There are two approaches to leveraging the contents of the PCR bank. The transparent approach assumes detailed knowledge of the boot process and of the software that is expected to be present on the system. With a transparent approach it is possible to predict the contents of the PCR bank by performing the same extension operations in software. The opaque approach does not assume detailed knowledge of the boot process, but 7 requires confidence that the system is currently running trusted software. With an opaque approach it is possible to simply record the current contents of the PCRs and compare them to the contents after future boots. With a careful implementation of either approach, it is possible for system administrators who install anti-virus and intrusion detection software to trust that the computing environment is not being manipulated by malware running at a lower level in the software stack. 1.4 Remote Attestation It is important to consider the security of the public key used to verify TPM quotes. If software running a TPM-enabled server relies on the AIK public key to verify TPM quotes, it is still vulnerable to malware at a lower level hiding the real TPM and providing instead a software-simulated TPM, replacing the corresponding public key with a public key for the simulated TPM. Due to the nature of software-based security, it is impossible to completely eliminate this possibility for software running on the same machine. A practical solution to this problem is called Remote Attestation, in which an external party verifies the quote. In a Remote Attestation model, software running on a server does not attempt to determine whether its own platform is trusted. Instead, it allows challengers external to the platform to request TPM quotes from the platform and it is the responsibility of challengers to verify the authenticity of the TPM quote and to make trust decisions based on its contents. Challengers must have a means to determine that the AIK used to sign the quote is protected by a real TPM, and they must be able to determine whether the contents of the server’s PCR bank indicate that the server is running only trusted software. 8 Before Remote Attestation can take place, the challenger must first authenticate the server’s TPM. This involves requesting a “proof” from the server that the TPM is authentic. The proof may include an Endorsement Key from the manufacturer, the Attestation Identity Key, as well as Conformance Credential and Validation Credential from quality assurance laboratories [9]. The protocol for Remote Attestation is that the challenger creates a challenge comprised of an encrypted nonce and list of PCRs to be quoted. A nonce is a number that is used only once within the context of a cryptographic system, in this case to prevent replay attacks. The challenger sends the challenge to the remote server. Because the challenge is encrypted using the AIK public key, and because the corresponding AIK private key is usable only by the remote server’s TPM, the remote server must use its TPM to decrypt the challenge. The remote server also uses its TPM to generate a quote for the requested PCRs. The response is the TPM quote, which contains the decrypted challenge and the selected PCR values as shown in Figure 4. The quote is digitally signed by the AIK private key. The remote server sends the response to the challenger. The challenger verifies the quote using the known AIK public key and the challenge nonce. 9 Figure 4. Illustration of a TPM Quote 1.5 Motivation In cloud computing, and other client/server environments in which it is desirable to implement Remote Attestation, there is a very prominent inconvenience: clients must not only be able to associate the contents of the server’s PCR bank to known combinations of trusted software, but also that association must be checked each time the client must make a decision to trust a server, and the client must verify the server AIK used to sign the quotes belongs to a real TPM. This adds a lot of complexity to even the simplest client/server applications. This project is motivated by the desire to use Remote Attestation in cloud computing and client/server environments without adding complexity to clients. 1.6 Goal The goal of this project is to develop a system in which a client may rely on Remote Attestation to make trust decisions without adding the above-mentioned complexity. Specifically, since the TLS protocol implementation is ubiquitous in clients, it is the goal 10 of this project to develop a system in which clients leverage TLS and its related infrastructure in order to verify a server’s platform characteristics in addition to its identity on every connection to a remote server, as shown in Figure 5. Figure 5. Client view of server using trust authority 11 Chapter 2 2. ARCHITECTURE 2.1 Transport Layer Security Every connection using Transport Layer Security (TLS) begins with a handshake in which the client and server agree on an encryption key to protect the connection [13]. The handshake is a critical event because it aims to ensure the confidentiality and integrity of the connection. The TLS handshake ends successfully when the client and server have agreed on a set of cryptographic algorithms and protocols to use for the connection, have authenticated each other, and have agreed upon a share secret key to encrypt data transmitted between them [13]. The TLS protocol has evolved since its inception as the Secure Sockets Layer (SSL) to mitigate new threats as they are discovered. In order to preserve compatibility with older clients and servers, many clients and servers typically allow a handshake using a previous version of the protocol and do not strictly require using only the latest version. This compatibility-preserving behavior has been used to attack TLS connections, by intercepting the protocol negotiation phase of the handshake and impersonating to both sides that the other side only supports older versions of TLS or SSL -- versions that have exploitable vulnerabilities [14]. In order to defend against this attack, the protocol proposed in this project is only defined for TLS 1.2 as specified in RFC 5246, with the additional requirement that both clients and servers be configured to reject previous versions of the protocol, namely SSLv2 [15] and SSLv3. 12 In a TLS connection, the server must typically authenticate itself to the client. In some environments, clients must also authenticate themselves to the server. This project focuses on the integration of Remote Attestation into server authentication, and leaves the integration of Remote Attestation into client authentication for future work. The authentication in TLS is implemented using RSA encryption. The server generates an RSA key pair, which is comprised of one private key and one public key. The private key is stored on the server and the public key is either provided to its clients or certified by an authority as shown in Figure 6. The key pairs have the characteristic that data encrypted using the public key can only be decrypted using the private key. In TLS, clients authenticate the server by sending a challenge encrypted using the server’s public key which is known to the client. If the server is able to decrypt the challenge and reply with its decrypted contents, it demonstrates possession of the corresponding private key. Figure 6. Relationship of Client, Server, and Certificate Authority It is important to note that server authentication in TLS only provides trust in the identity of the server. In order for the client to verify that the server is running specific software that is trusted to comply with the client’s security expectations, other mechanisms are needed. However, if it’s possible to secure the server’s TLS private key such that it is 13 only usable when the server is running trusted software, then a successful TLS connection requires use of that private key to decrypt the client’s challenge and thus demonstrates that the server is indeed running trusted software, as shown in Figure 7. Figure 7. Combining TLS and TPM 2.2 Trusted Platform Module The Trusted Platform Module (TPM) is a hardware-based root of trust for a computing platform. In this project, the platform containing the TPM is the remote server. The TPM can create and store RSA private keys and has a bank of 24 registers. Each register is called a Platform Configuration Register (PCR) and can only be reset internally by the TPM. All other software and hardware external to the TPM can only extend the value of the register. This means that the current value of any PCR is a consequence of the entire history of extensions to that PCR since power-on. The TPM is also able to provide 14 digitally signed reports of the current contents of all or selected PCRs. These digitally signed reports are also called quotes. The remote server administrator uses the TPM to create at least one special-purpose RSA key called an Attestation Identity Key (AIK), and when a quote is requested it is signed using the AIK private key. It is important to note that the AIK private key is only readable to the TPM. Digital signatures produced by a TPM are therefore considered secure once the AIK public key has been verified as belonging to a real TPM. There are two distinct ways to verify that an AIK comes from a real TPM. The first way is to use a Privacy CA [9]. The Privacy CA maintains a directory of all TPM manufacturers and their endorsement certificates. The endorsement certificates are X.509 certificates containing RSA public keys corresponding to the endorsement keys that manufacturers place in the TPM. In the case that a manufacturer has not provided an endorsement credential, or has not published its endorsement certificate, it is possible for the system administrator to create a local endorsement key and corresponding certificate, and then generate endorsement credentials to import into the TPM. The local administrator must then coordinate with the Privacy CA to add the local endorsement certificate to the list of known manufacturers. The second way is to use a mechanism called Direct Anonymous Attestation (DAA) which relies on a group signature scheme [16] to prove that a TPM is a member of a group known as real TPMs, and can handle compromised keys [17]. For this project, it does not matter which of the two mechanisms is used to verify the AIK. 15 The TPM’s ability to create new RSA key pairs is complemented by its ability to protect the private keys in different ways. The protection to apply to a private key is determined at the time the key is created by the person or software that requested creation of the key. A private key can be migratable or non-migratable. A migratable private key can be exported by the TPM in an encrypted format that can then be imported by another TPM. A non-migratable key can only be exported in an encrypted format that is readable only by the same TPM. A private key can be protected so that it can only be used to encrypt and decrypt data on the same platform on which it was created, and only when the PCR bank has specific contents. This is called sealing. It’s possible to seal a key to the PCR bank’s current contents or to any other contents, such as expected future contents [10]. A sealed key can only be used when the PCR bank’s contents match the conditions specified by the sealed key. This is enforced internally by the TPM. When data is encrypted using a sealed key, it is called sealed data. If a private key is used to encrypt data that is bound to the local TPM but not to any specific PCR contents, it is called a binding key. Because the contents of the PCR bank, also known as PCR values, are formed during the boot process, the PCR values reflect the combination of software running on the system. According to the TCG specification, TPMs are shipped disabled and must be enabled by the owner of the hardware in an opt-in system [9]. In order to enable the TPM, the system owner must reboot the server and enter the BIOS configuration screen in order to clear and enable the TPM. Many TPM operations require an authorization password, starting 16 with the act of taking ownership of the TPM after enabling it. Therefore, use of the TPM strongly implies the authorization of the system owner. 2.3 Trust It is the client’s responsibility to define what constitutes a trusted server. The client must associate specific PCR contents with a trust indication -- either trusted or untrusted. In practice, at least one PCR and its content must be defined as indicating that the server is running trusted software. It is not necessary to maintain a list of untrusted platforms because anything that is not explicitly listed as trusted is considered to be untrusted. The server administrator must know what PCR values correspond to trusted software, either by using the transparent method or the opaque method. The transparent method requires detailed knowledge of the platform boot process and digests of all measured components in order to compute an expected PCR value. The opaque method requires provisioning a trusted system in an isolated environment and recording its PCR values as a trusted configuration. For this project, it does not matter which method is used to determine the trusted PCR values, but the opaque method was chosen for its simplicity. In real-world use, the opaque method could be cumbersome to manage for a large number of servers with different configurations. The server administrator must securely distribute the trusted server certificate to clients. Clients using the certificate must trust that the proper verification was done for the server’s platform characteristics as well as its identity. 17 2.4 Remote Attestation Before sending data to a remote server, a client must first verify that the remote server is running trusted software. This is accomplished using Remote Attestation. The typical procedure for Remote Attestation is that the client, having knowledge of the server’s AIK, sends a challenge to the server accompanied by a list of PCRs that should be quoted. The server forwards the challenge to the TPM and obtains the TPM quote, which contains the contents of the specified PCRs, the challenge, and a digital signature created by the AIK that covers both the PCR contents and the challenge. The server replies to the client with the TPM quote. The client then verifies the quote using the server’s known AIK. As time passes since the creation of a TPM quote, the chance that the server’s state has changed continues to increase. If old TPM quotes are used in decision-making, the client risks that the server is no longer in a trusted state. Therefore, unless the client has an assurance that the server has not changed since the last quote, a TPM quote must be obtained each time a client makes a decision to trust the server. In this project, the goal is to avoid the need to perform the quoting procedure each time the client connects to a remote server. If the server seals a private key to a specific set of PCRs and the client associates the corresponding public key to the same set of PCRs, and if that key pair is used to authenticate the server during a TLS connection, then the client knows that successful connections demonstrate the server is running trusted software. In order to avoid adding complexity to the client, the task of associating the server key to a set of PCRs is delegated to a trust authority, which then issues a certificate to the server as shown in Figure 8. 18 Figure 8. Provisioning client and server certificates 2.5 Certificates In TLS, the server sends its public key to the client. However, if the client does not already know the server’s public key, it cannot trust a key provided by the server. This is because an attacker can intercept the handshake and can provide its own public key instead of the server’s public key [18]. The client would then encrypt the challenge using the attacker’s public key, which the attacker could trivially decrypt and reply with the correct decrypted content. To mitigate this threat, clients need either a trusted directory of server public keys that can be referenced when connecting to a new server, or a way to verify that a particular public key is associated with a particular server. Internet servers typically obtain certificates from a well-known company, called a Certificate Authority (CA), which associate the server’s public key with the server’s address. There are many such companies. The certificates are typically in a format called 19 X.509, which is comprised of the server’s address and public key, and a digital signature by the CA that authenticates the information on the certificate. Clients are responsible for maintaining a list of trusted CAs. When a client connects to a remote server, the client receives the server’s public key in X.509 certificate format that also includes the server’s address and the CA that issued the certificate. The client can then check that a listed CA issued the certificate, and once the CA is found in the list the client can use the CA public key to verify the digital signature on the server certificate. In this project, the trust authority is a CA that associates a set of PCR values comprising the trusted platform characteristics with the server identity, and issues a server certificate that covers both. 2.6 Summary The project integrates the TLS protocol and the TCG specification to create a mechanism that allows a client to assert that a server is running trusted software simply by successfully establishing a TLS connection with that server. The project is comprised of the following components: server, trust authority, and client. The server administrator creates an RSA key pair in which the private key is sealed by the TPM to a specified set of PCR values indicating the server is running trusted software. The public key is submitted to the trust authority for certification. The trust authority verifies that the public key submitted by the server corresponds to a private key sealed by that server’s TPM to a specific set of PCR values, and that the server’s AIK corresponds to a real TPM. The trust authority sends a quote request to the server, including an encrypted random nonce as the challenge and the specified set of 20 PCR values. When the trust authority receives the TPM quote reply from the server, it can verify that the server’s PCR values are trusted and it knows the server’s AIK. The trust authority then signs the server’s public key. The trust authority must be trusted by the client to provide assertions of the server’s platform characteristics, namely its PCR contents, and the fact that the server’s TLS private key is sealed to a specific set of PCR values. The trust authority maintains a list of PCR values indicating the server is trusted. The client maintains a list of trust authorities. When the client connects to the server, it follows the normal TLS procedure of checking that the server certificate was signed by a trusted CA, in this case a trust authority. Unlike typical TLS applications, if the server certificate is not signed by the trust authority, it must be rejected - the user must not be prompted to accept the certificate. This is usually a configurable behavior in TLS libraries used by application software. The client can then connect to the server using TLS and have assurance that the server’s private key is sealed in the TPM to a set of PCR values that indicates the server is running trusted software. 21 Chapter 3 3. IMPLEMENTATION To demonstrate real-world usage, the trust authority, server, and client, should be installed on separate computers. It is also possible to install them all on a single computer in order to quickly experiment with the solution proposed by this project. 3.1 Trust Authority When a server requests a trust certificate, the trust authority must challenge the server and evaluate the response. In this section, the trust authority will be prepared to receive requests. The procedure for approving requests will be detailed in a later section. 3.1.1 Install OpenSSL The OpenSSL library is required for compiling the source code provided with this project and the OpenSSL tool is required for following the procedure outlined below. Please see Appendix D, OpenSSL, for detailed instructions on how to download and install OpenSSL. 3.1.2 Build the source code published in Appendix A The aikchallenge and aikqverify tools will be needed to authenticate the server’s AIK and platform characteristics. Due to the fact that server used to test this project has a TPM with an endorsement key for which the manufacturer has not published a complete certificate chain, the aikchallenge program was modified to allow skipping the endorsement certificate validation. This hack should be disabled for real-world use. The commands to build the tools are: gcc -o aikchallenge aikchallenge.c -lcrypto 22 gcc -c aikqverify.c gcc aikqverify.o -o aikqverify -lcrypto -ltspi 3.1.3 Create the trust authority key pair The trust authority private key will be used to sign server certificates. In the following steps, openssl prompts for a password. The trust authority administrator can choose any password, but it must be remembered in order to sign certificates later. In the commands below, a backslash at the end of a line indicates the next line is a continuation. openssl genrsa -des3 -out ca.key 1024 openssl req -new -key ca.key -subj "/C=US/ST=California/L=Sacramento/O=CSUS/OU=ECS/CN=TrustAuthority" \ -out ca.csr openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt echo 01 > serial echo >> serial 3.1.4 Publish the CA certificate It is assumed from this point on that a copy of the file ca.crt is provided to all clients securely. It is important to copy it securely because if an attacker intercepts the CA certificate and replaces it with the attacker’s own certificate, the attacker will be able to create its own server certificate with fake PCR contents and it will accepted by victims. The secure copy mechanism can be SFTP, SSH, or by telephone confirmation of certificate fingerprints. 23 3.2 Server The server used in this project is running GNU/Linux 2.6. The server must be initialized with the following sequence of actions: - Install OpenSSL, Trousers, Trousers TPM Tools, and the Trousers TPM Engine for OpenSSL - Build the source code published in Appendix A - Enable the TPM and take ownership - Create an AIK - Create a TLS key pair sealed to current PCR values - Submit TLS public key to trust authority for certificate - Install TLS certificate - Listen for TLS client connections using TLS certificate Detailed instructions to complete each step are provided in this section and supplemented in the appendices. 3.2.1 Install OpenSSL and Trousers Please see Appendix D, OpenSSL, for detailed instructions on how to download and install OpenSSL. Please see Appendix E, Trousers, for detailed instructions on how to download and install Trousers, Trousers TPM Tools, and Trousers TPM Engine for OpenSSL. 24 3.2.2 Build the source code published in Appendix A Build the source code published in Appendix A. This step requires the OpenSSL and Trousers libraries. The tss_err.o file is created by the TPM Quote Tools package. In the commands below, a backslash at the end of a line indicates the next line is a continuation. gcc -c hex.c -o hex.o gcc -c config.c gcc -o hex2bin hex2bin.c gcc -o showpcr showpcr.c -ltspi gcc config.o hex.o -o extendpcr extendpcr.c -ltspi gcc config.o hex.o -o create_tpm_key create_tpm_key.c -ltspi -lssl gcc getcert.o remote.o tss_err.o config.o hex.o -o getcert -lcrypto -ltspigcc config.o \ hex.o -o aikpublish aikpublish.c -ltspi gcc config.o hex.o -o aikrespond aikrespond.c -ltspi 3.2.3 Enable the TPM and take ownership Enable the TPM and take ownership using the procedure described by Habets [2]. If the BIOS software on the server has TPM support, the TPM must be enabled using the BIOS [3]. If the BIOS software lacks TPM support, the following commands provided by TPM Tools can be used. Fig. 9 illustrates sample output from the tpm_version tool. tpm_version tpm_setpresence --assert tpm_clear --force tpm_setenable --enable --force 25 tpm_setactive --active tpm_takeownership -u -y TPM 1.2 Version Info: Chip Version: 1.2.8.8 Spec Level: 2 Errata Revision: 2 TPM Vendor ID: STM TPM Version: 01010000 Manufacturer Info: 53544d20 Figure 9. Output of tpm_version A lot of the commands used next require the TPM owner password. To prevent the password from appearing in the Linux process list, the programs must either prompt for the password, or read it from an environment variable, or read it from a file. Switch to the /var/local directory where the work will be done and write the TPM owner password into the file tpm.owner.secret using an editor such as vi. 3.2.4 Create the AIK Create the AIK in /var/local . The getcert command takes a single parameter that is the file to which to write the endorsement certificate. The aikpublish command takes the endorsement certificate file as input, and produces two files: aik.proof is a public file containing the AIK public key, information about the TPM, and a copy of the endorsement certificate; aik.blob is an encrypted file containing the AIK private key. cd /var/local getcert ekcert aikpublish ekcert aik.proof aik.blob 3.2.5 Create the sealed TLS private key Create a TLS key pair sealed to current PCR values. Fig. 10 illustrates sample output. 26 showpcr 0 17 18 19 20 > pcr.manifest 0 17 18 19 20 891eb0b556b83fcef1c10f3fa6464345e34f8f91 bfc3ffd7940e9281a3ebfdfa4e0412869a3f55d8 dc3831d76dbb34f8906c1f9e14fc99ed227bb817 064d4c4f0eecb20a1d2b512ae80d7df6af612d01 0000000000000000000000000000000000000000 Figure 10. Content of pcr.manifest create_tpm_key ssl.tpm.key The create_tpm_key command automatically uses the pcr.manifest file in the current directory. This should be improved in future work to accept command line parameters for the PCR list and the owner authorization secret file. The output of the create_tpm_key command is a file that contains an encrypted private key and a public key. The encrypted private key can only be read by the TPM. 3.2.6 Request the TLS certificate Use OpenSSL to create a Certificate Signing Request (CSR). In the command below, the subject is arbitrary but the CN component should be set to the server’s IP address or DNS hostname, whichever will be used by clients to access the server. openssl req -keyform engine -engine tpm -key ssl.tpm.key -new -subj "/C=US/ST=California/L=Sacramento/O=CSUS/CN=192.168.1.42" -out ssl.tpm.csr A CSR is signed by the private key, which is sealed to specific PCR values. If the current PCR values do not match those to which the key was sealed, the command will fail with an error message similar to that shown in Fig. 11. 140673387628360:error:8006906D:tpm engine:TPM_RSA_PRIV_ENC:request failed:e_tpm.c:1104: 140673387628360:error:0D0C3006:asn1 encoding routines:ASN1_item_sign:EVP lib:a_sign.c:279: Figure 11. Example of failure to use sealed TPM private key 27 Submit the CSR to the trust authority and receive the signed certificate. In a demonstration, this requires copying the files aik.proof, and ssl.tpm.csr to the trust authority, following the attestation steps in section 3.3, creating the certificate, and copying the certificate to the server. The certificate filename is assumed to be ssl.tpm.crt. 3.2.7 Install the TLS certificate For demonstration, the TLS certificate can simply be copied from the trust authority to the server. In real-world use, it would further need to be placed in a location specific to the web server software in use. 3.2.8 Listen for TLS connections Use the OpenSSL s_server tool to listen for TLS connections. In the command below, the backslash at the end of a line indicates the next line is a continuation. openssl s_server -accept 7777 -tls1 -cert ssl.tpm.crt -key ssl.tpm.key -CAfile ca.crt \ -keyform engine -engine tpm In real-world use, the HTTP server would be configured to use ssl.tpm.key with the OpenSSL TPM Engine. For example, the mod_ssl module of the Apache Http Server has a configuration parameter called SSLCryptoDevice that can be set to the value “tpm” in order to achieve something equivalent to the command line shown above. 3.3 Attestation The attestation process happens between the trust authority and the server that requests a trust certificate. When the trust authority receives a certificate request, it must verify the private key corresponding to the request is protected by a real TPM. 28 3.3.1 Challenge the AIK public key These steps are performed by the trust authority upon receiving a CSR from a server. Create a challenge secret comprised of 32 random bytes. openssl rand 32 > aik.challenge.secret The aikchallenge command encrypts the challenge secret using the AIK public key which is embedded in the aik.proof file. It outputs the encrypted challenge, as well as the AIK public key into a separate file in PEM format. aikchallenge aik.challenge.secret aik.proof aik.challenge aik.pubkey It’s possible to examine the contents of the AIK public key with this command: openssl rsa -in aik.pubkey -text -pubin –noout Sample output from the openssl command is shown in Fig. 12. Public-Key: (2048 bit) Modulus: 00:ab:71:8e:e9:1e:4a:83:00:83:e6:0a:16:6d:8c: 24:0d:c9:75:45:e1:5a:5d:b3:9f:c0:43:c8:1a:a6: 34:c8:b9:a4:db:2f:1f:e1:6f:5c:81:9b:16:67:23: df:4f:d8:51:2a:8b:67:64:b6:c9:84:cf:1c:7c:29: b5:4d:17:0c:ad:d2:ff:d7:af:36:2c:96:48:93:9e: b1:a4:6d:2e:fe:8c:2c:ad:79:be:c1:49:58:a3:dd: 61:71:ee:00:8c:fd:20:05:45:3d:d9:74:be:d2:fe: 2b:29:4c:d0:43:63:be:5c:91:d8:23:3a:d0:a1:4c: 10:1a:8a:42:41:29:49:15:09:58:91:9e:76:f9:ad: 95:5a:7e:10:fc:ed:f7:37:60:68:b0:8c:0d:d6:52: cd:e6:28:d0:c3:b7:78:1b:11:8a:26:05:ec:cd:75: d5:be:3e:ec:d0:d3:86:b0:18:be:90:72:5b:dd:8a: ca:74:7f:95:45:1c:a9:3e:28:69:f9:90:4a:09:a7: 62:a5:22:a3:52:5e:05:5a:2a:74:7d:0e:ca:9c:db: dd:b4:1a:fc:15:99:df:93:ff:9a:32:c1:f0:50:76: ee:51:f3:21:a1:c9:92:3f:fc:1f:c4:4a:74:c2:4f: af:fc:1d:96:fd:2b:ad:48:e7:ee:73:20:17:7e:b4: c2:39 Exponent: 65537 (0x10001) Figure 12. Output of openssl rsa -in aik.pubkey -text -pubin -noout Copy the aik.challenge file to the server that requested the certificate. 29 3.3.2 Create a TPM Quote These steps are performed on the server after receiving the aik.challenge file. The aikrespond tool uses the files aik.blob and aik.challenge as inputs and produces the file aik.challenge.response as output. aikrespond aik.blob aik.challenge aik.challenge.response The output file aik.challenge.response is the decrypted challenge. Having decrypted it, the server will now use it as nonce in a TPM quote. The list of PCRs mentioned in the following command line is the list that will be certified by the trust authority if the request is approved. The command is shown here: aikquote -c aik.challenge.response aik.blob 0 17 18 19 20 aik.quote Copy the aik.quote file to the trust authority. 3.3.3 Verify the TPM Quote These steps are performed on the trust authority after receiving the file aik.quote from the server. Verify the TPM quote by checking that it includes the decrypted nonce from aik.challenge.secret, and that it was signed by the AIK private key corresponding to aik.pubkey. The command is shown here: aikqverify -c aik.challenge.secret aik.pubkey aik.quote If the aikqverify command succeeds, it will display a list of PCR contents that were quoted, as shown in Fig. 13. These are the PCR contents that the server requests to be certified. 30 0 891eb0b556b83fcef1c10f3fa6464345e34f8f91 17 bfc3ffd7940e9281a3ebfdfa4e0412869a3f55d8 18 dc3831d76dbb34f8906c1f9e14fc99ed227bb817 19 064d4c4f0eecb20a1d2b512ae80d7df6af612d01 20 0000000000000000000000000000000000000000 Success! Figure 13. Output of aikqverify Create the server’s TLS certificate. In the following command, a backslash at the end of a line indicates the next line is a continuation. openssl x509 -req -days 365 -in ssl.tpm.csr -CA ca.crt -CAkey ca.key -CAserial \ serial -out ssl.tpm.crt Copy the certificate file ssl.tpm.crt to the server. 3.4 Client The client must have at least one trust authority certificate in order to verify server TLS certificates. The file ca.crt is the trust authority certificate. Open a connection to the server: openssl s_client -connect 192.168.1.42:7777 -tls1 -CAfile ca.crt If the connection succeeds, the server has demonstrated possession of a private key whose corresponding public key was certified by the trust authority. Refer to Appendix B for example output of client and server connections. 3.5 Trust A successful TLS connection indicates the server is trusted. The client must assume that the trust authority properly verified that the server has a real TPM and that the server’s TLS private key is sealed in the TPM with specific PCR contents for which a certificate was issued. 31 Chapter 4 4. CONCLUSION This project outlines a system by which clients have some assurance that the servers they connect to are not only identified, but also that the server platform is in a specific configuration acceptable to the client. The configuration specification may include one or more of the 24 available Platform Configuration Registers provided by the Trusted Platform Module on the server. An authority that is trusted by the client, called a trust authority, verifies the server platform configuration. The trust authority verifies the server’s credentials and platform configuration, and if the configuration is acceptable it issues an X.509 certificate to the server to use with Transport Layer Security (TLS) connections. The server’s Trusted Platform Module seals server private key corresponding to the certificate so that it can only be used when the server platform is in the same specific configuration that was certified. Clients equipped with a copy of the trust authority’s own X.509 certificate can connect to certified servers. One step in creating a TLS connection is verifying the server certificate with known certificate authorities. If the trust authority certificate successfully verifies the server certificate, and if the server is able to demonstrate possession of the corresponding private key by decrypting the challenge sent as part of the TLS protocol, then the server demonstrates that its current platform configuration matches the certificate. 32 These results were achieved using a variety of open source command line tools. Some of the open source tools were modified, and those modifications as well as original code written for this project are all included in Appendix A, Source Code. There is a lot of room for improvement. Some ideas are mentioned in Chapter 5, Future Work. 33 Chapter 5 5. FUTURE WORK 5.1 Runtime Measurement The operating system should measure every executable before it is started. A PCR should be designated for runtime measurements and extended with each executable program’s measurement. If the executable program’s measurement was already extended into the runtime PCR, then it should be skipped. So the runtime PCR value would be the set of programs executed within the operating system, ordered according to the time of first execution of each program, with each program being considered only once. 5.2 User-Space Measurement The operating system should measure every executable before it is started. The list of authorized executable programs is what should be extended into the PCR. If an executable is not on the list, then the PCR must be extended. 5.3 Global Knowledge Every software program is created by an individual or organization and is copied by everyone else. It should be possible to create a public directory of known programs, with their digests signed by the authors. This should include drivers, kernels, and even wellknown trusted configuration files. 5.4 Client Attestation In some situations, servers may require proof that clients are running trusted software. For example, streaming media servers that provide copyrighted content may want 34 assurances that the clients are running software that is trusted to respect the copyright and prevent unauthorized use. 5.5 PCR Contents as X.509v3 Extensions Clients validate a server certificate by checking that it is present in a list of trusted certificates or is signed by a trusted authority, just as they already do with any other server TLS certificate. A more dynamic approach to trusting servers is also possible using X.509v3 extensions. When the trust authority certifies a server’s TLS public key, it should use X.509v3 extensions to annotate the certificate with the PCR contents that were quoted by the server during the attestation process. This change would enable clients to keep track of which certificate indicates which trusted state without having to maintain additional metadata. Clients could implement a more dynamic certificate validation function that checks the certificate was issued by a trusted authority and then checks the annotated PCR contents against a list of trusted platform characteristics. This would require clients to maintain only a list of one or more trusted authorities and a list of trusted platform characteristics represented as PCR values. 5.6 Software Updates In data center environments, uptime is a critical measure of performance, and CPU utilization is a profit factor that must be maximized. Furthermore, there are typically many servers that are identical in terms of the hardware and software used. When there are software updates, they are typically tested on a small set of servers and then replicated to similar servers throughout the data center. This leads to an issue with trust certificates: 35 unlike regular TLS certificates, trust certificates are bound to the software running on the server. Assuming that the trust authority implements a trust policy involving both BIOS and operating system, updates to these will invalidate the TLS certificates and new certificates must be issued. The PCR contents of the small group of test servers can be used to create a new list of PCR contents that indicate trusted software. As servers are upgraded and request new certificates, the quote and attestation process can be automated and new certificate requests for servers whose PCR contents match an approved list can be automatically approved. 5.7 Automation The sequence of steps outlined in this project is very lengthy. Much of it can be automated into just a few commands, which can even be executed automatically during provisioning of servers in order to certify their platform configuration. 5.8 Trust But Verify Paranoid clients should be able to perform the same verifications as the trust authority. This requires support on the server to answer challenges from all clients. However, because a server can have only one TLS certificate per IP address, there can be only one trust authority that provides a server TLS certificate. After verifying the server’s trust status independently, the client could then store the server TLS certificate in a trusted certificate repository. 36 APPENDICES 37 APPENDIX A APPENDIX A. SOURCE CODE List of files: config.h config.c hex.h hex.c hex2bin.c showpcr.c extendpcr.c aikpublish.c aikchallenge.c aikrespond.c aikquote.c aikqverify.c create_tpm_key.c 38 config.h /* * Copyright (c) 2013 Jonathan Buhacoff * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __CONFIG_H_ #define __CONFIG_H_ char* read_owner_secret(char *configPath); void read_pcr_manifest(char *configPath, char *filename, TSS_HPCRS *hPcrs); struct bytearray read_binary_data(char *path); #endif 39 config.c /* * Copyright (c) 2013 Jonathan Buhacoff * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include <stdio.h> <string.h> <memory.h> <trousers/tss.h> <openssl/x509.h> <sys/types.h> <sys/stat.h> <unistd.h> "config.h" "hex.h" // from create_tpm_key.c: #define print_error(a,b) \ fprintf(stderr, "%s:%d %s result: 0x%x (%s)\n", __FILE__, __LINE__, \ a, b, Trspi_Error_String(b)) // secrets larger than 20 bytes need to be hashed with sha1 ... we don't implement that yet #define MAX_SECRET_LENGTH 20 // you must call free() on the return value when you are done with it char* append_path(char *path, char *filename) { size_t newpath_size = snprintf(NULL, 0, "%s/%s", path, filename) + 1; // +1 for null terminator char *newpath = malloc( newpath_size * sizeof(char) ); snprintf(newpath, newpath_size, "%s/%s", path, filename); return newpath; } // You must call free() on the return value when you are done with it char* read_owner_secret(char *configPath) { char *filename = "tpm.owner.secret"; char *path = append_path(configPath, filename); //printf("opening file %s\n", path); FILE *file = fopen(path, "rb"); if (file == NULL) { fprintf (stderr, "Unable to read %s\n", path); exit (1); } 40 struct stat fileInfo; fstat(fileno(file), &fileInfo); if( fileInfo.st_size > MAX_SECRET_LENGTH ) { fprintf(stderr, "Owner secret larger than max length %d\n", MAX_SECRET_LENGTH); exit(1); } char *content = malloc( (fileInfo.st_size+1) * sizeof(char) ); //int count = 0; //int n = 0; //while(!feof(file) && count < MAX_SECRET_LENGTH) { //n = fread(content, sizeof(char), MAX_SECRET_LENGTH, file); //count += n; //} size_t nread = fread(content, sizeof(char), MAX_SECRET_LENGTH, file); fclose(file); //printf("read %d bytes from %s\n", nread, path); free(path); return content; } // TODO: move this to an io.c file // You must call free() on the return value when you are done with it struct bytearray read_binary_data(char *path) { FILE *file = fopen(path, "rb"); if (file == NULL) { fprintf (stderr, "Unable to read %s\n", path); exit (1); } struct stat fileInfo; fstat(fileno(file), &fileInfo); struct bytearray content; content.length = fileInfo.st_size; content.data = malloc( fileInfo.st_size * sizeof(unsigned char) ); size_t nread = fread(content.data, sizeof(unsigned char), fileInfo.st_size, file); fclose(file); return content; } void read_pcr_manifest(char *configPath, char *filename, TSS_HPCRS *hPcrs) { TSS_RESULT result; char *path = append_path(configPath, filename); FILE *file = fopen(path, "rb"); if( file == NULL ) { fprintf(stderr, "Unable to read %s\n", path); exit(1); } struct pcr_list pcrs = read_pcr_list(file); print_pcr_list(pcrs); int i; for(i=0; i<pcrs.length; i++) { result = Tspi_PcrComposite_SetPcrValue(*hPcrs, pcrs.value[i].index, SHA1_LENGTH, (BYTE *)pcrs.value[i].hash.data); if( result != TSS_SUCCESS ) { print_error("Tspi_PcrComposite_SetPcrValue", result); } } free(path); } 41 hex.h /* * Copyright (c) 2013 Jonathan Buhacoff * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __HEX_H__ #define __HEX_H__ #define SHA1_LENGTH 20 typedef unsigned char byte; struct bytearray { byte *data; unsigned int length; }; struct pcr { unsigned int index; struct bytearray hash; }; struct pcr_list { struct pcr *value; unsigned int length; }; void zero_bytearray(struct bytearray array); struct bytearray create_sha1_bytearray(); void free_bytearray(struct bytearray array); struct pcr create_pcr(unsigned int index); void free_pcr(struct pcr hPcr); struct pcr_list create_pcr_list(unsigned int size); void free_pcr_list(struct pcr_list pcrs); void unsignedchararray2hex(unsigned char *source, unsigned int srclen, char *target); void bytearray2hex(struct bytearray source, char *target); void hex2bytearray(char *source, unsigned int srclen, struct bytearray target); struct pcr_list read_pcr_list(FILE *in); void print_pcr_list(struct pcr_list pcrs); #endif 42 hex.c /* * Copyright (c) 2013 Jonathan Buhacoff * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include <stdio.h> <stdlib.h> <ctype.h> <string.h> "hex.h" void zero_bytearray(struct bytearray array) { int i; for(i=0; i<array.length; i++) { array.data[i] = 0; } } struct bytearray create_sha1_bytearray() { struct bytearray hash; hash.data = malloc( SHA1_LENGTH * sizeof(byte) ); hash.length = SHA1_LENGTH; return hash; } void free_bytearray(struct bytearray array) { free( (void *)array.data ); } struct pcr create_pcr(unsigned int index) { struct pcr hPcr; hPcr.index = index; hPcr.hash = create_sha1_bytearray(); return hPcr; } void free_pcr(struct pcr hPcr) { free_bytearray( hPcr.hash ); } struct pcr_list create_pcr_list(unsigned int size) { struct pcr_list pcrs; pcrs.length = size; pcrs.value = malloc( pcrs.length * sizeof(struct pcr) ); unsigned int i; for(i=0; i<pcrs.length; i++) { pcrs.value[i] = create_pcr(i); } 43 return pcrs; } void free_pcr_list(struct pcr_list pcrs) { unsigned int i; for(i=0; i<pcrs.length; i++) { free_pcr(pcrs.value[i]); } } void unsignedchararray2hex(unsigned char *source, unsigned int srclen, char *target) { char buf[3]; // 2 hex digits and null terminator unsigned int i; for(i=0; i<srclen; i++) { sprintf(buf, "%02x", source[i]); target[i*2] = buf[0]; target[(i*2)+1] = buf[1]; } target[i*2] = '\0'; } // target must have be at least source.length * 2 bytes long and probably should also leave space for null terminator void bytearray2hex(struct bytearray source, char *target) { unsigned int i; for(i=0; i<source.length; i++) { sprintf(&target[i*2], "%02x", source.data[i]); } target[i*2] = '\0'; } // ignores non-hex digits; requires even-length hex representation (leading zeros to make it line up) void hex2bytearray(char *source, unsigned int srclen, struct bytearray target) { unsigned int s,t=0; for(s=0; s<srclen-1; s+=2) { if( !isxdigit(source[s]) || !isxdigit(source[s+1]) ) { printf("illegal argument: not a hex: %s\n", source); exit(1); } int b; sscanf(&source[s], "%2x", &b); target.data[t] = b; //printf("source: %c%c target: %d\n", source[s], source[s+1], target.data[t]); // debug t++; } //printf("\n"); // debug } /* Format of pcr list (aka manifest) file: # optional comment pcr-index pcr-value pcr-index pcr-value # optional comment ... There can be one or more leading and trailing spaces around each value. Blank lines are ignored. Lines starting with hash # are ignored. If a hash # apppears at the end of a valid line the rest of the line is ignored. */ struct pcr_list read_pcr_list(FILE *in) { int pcrset[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; struct pcr_list pcrs = create_pcr_list(24); char linebuf[255]; fgets(linebuf, 255, in); // read first line while( !feof(in) && !ferror(in) ) { if( linebuf[0] == '#' || linebuf[0] == '\n' ) { goto readnextline; } 44 unsigned int pcrIndex; char hex[40]; sscanf(linebuf, "%d %40s\n", &pcrIndex, hex); pcrset[pcrIndex] = 1; hex2bytearray(hex, 40, pcrs.value[pcrIndex].hash); readnextline: fgets(linebuf, 255, in); } // now consolidate into just the pcrs that were read int count = 0; int i; for(i=0; i<24; i++) { count += pcrset[i]; } struct pcr_list pcrs1 = create_pcr_list(count); pcrs1.length = count; unsigned int next = 0; for(i=0; i<24; i++) { if( pcrset[i] ) { pcrs1.value[next].index = i; pcrs1.value[next].hash = pcrs.value[i].hash; next++; } else { free_pcr( pcrs.value[i] ); } } return pcrs1; } void print_pcr_list(struct pcr_list pcrs) { printf("# PCR manifest length: %d\n", pcrs.length); unsigned int i; for(i=0; i<pcrs.length; i++) { char buf[255]; bytearray2hex(pcrs.value[i].hash, buf); printf("%2d %s\n", pcrs.value[i].index, buf); //pcrs.value[i].hash); } } /* EXAMPLE CODE: #include "hex.h" int main(int argc, char **argv) { FILE *in = fopen("pcr.manifest", "rb"); struct pcr_list pcrs = read_pcr_list(in); print_pcr_list(pcrs); fclose(in); } */ /* SAMPLE DATA FILE: pcr.manifest [root@localhost ~]# cat pcr.manifest 0 891eb0b556b83fcef1c10f3fa6464345e34f8f91 17 bfc3ffd7940e9281a3ebfdfa4e0412869a3f55d8 # test whole line comment 18 dc3831d76dbb34f8906c1f9e14fc99ed227bb817 # optional comment 19 064d4c4f0eecb20a1d2b512ae80d7df6af612d01 20 0000000000000000000000000000000000000000 EXAMPLE EXECUTION: [root@localhost ~]# ./hex # PCR manifest length: 5 0 891eb0b556b83fcef1c10f3fa6464345e34f8f91 17 bfc3ffd7940e9281a3ebfdfa4e0412869a3f55d8 18 dc3831d76dbb34f8906c1f9e14fc99ed227bb817 45 19 064d4c4f0eecb20a1d2b512ae80d7df6af612d01 20 0000000000000000000000000000000000000000 */ 46 hex2bin.c /* * hex2bin - converts data in hexadecimal form to binary form * * Copyright (c) 2013 Jonathan Buhacoff * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include <stdio.h> #include <stdlib.h> /* Input must contain only hex characters. Any other characters will result in an error * printed to stderr and exit code 1. On success exit code is 0. * * Would be nice to add an option in the future to support hex files with * comment lines starting with #, and to ignore blank lines and newline characters. * * Example: * echo 1111111111111111111111111111111111111111 | hex2bin > /tmp/1.bin */ int main(int argc, char **argv) { int b; int scanerr = 0; while(1) { scanerr = fscanf(stdin, "%2x", &b); if( scanerr == EOF ) { break; } if( scanerr != 1 ) { fprintf(stderr, "non-hex input\n"); exit(1); } fputc(b, stdout); } exit(0); } 47 showpcr.c /* * showpcr - displays the current value of selected PCRs * * Copyright (c) 2013 Jonathan Buhacoff * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include <stdio.h> #include <trousers/tss.h> // this macro assumes the following variable declarations are in scope: // 1. TSS_HCONTEXT hContext // 2. TSS_RESULT result // how to use it: // TRY( Tspi_Context_Create(&hContext) ); #define TRY(a) \ result = a; \ if( result != TSS_SUCCESS ) { \ fprintf(stderr, "%s:%d error 0x%x (%s) from %s\n", __FILE__, __LINE__, \ result, Trspi_Error_String(result), #a); \ Tspi_Context_Close(hContext); \ exit(result); } void usage(char *argv0) { fprintf(stderr, "\t%s: show current state of selected PCRs\n" "\tusage: %s <pcrN> <pcrN> ...\n\n" "\tOptions:\n" "\t\tEach <pcrN> is a number between 0 and 23 inclusive\n", argv0, argv0); exit(-1); } // target buffer must be at least srclen*2 + 1 bytes void unsignedchararray2hex(unsigned char *source, unsigned int srclen, char *target) { char buf[3]; // 2 hex digits and null terminator unsigned int i; for(i=0; i<srclen; i++) { sprintf(buf, "%02x", source[i]); target[i*2] = buf[0]; target[(i*2)+1] = buf[1]; } target[i*2] = '\0'; } 48 int main(int argc, char **argv) { TSS_HCONTEXT hContext; TSS_HTPM hTPM; TSS_RESULT result; unsigned char *pcrval = NULL; uint32_t pcrlen; char hexbuf[255]; int i; if( argc == 1 ) { usage(argv[0]); exit(1); } TRY( Tspi_Context_Create(&hContext) ); TRY( Tspi_Context_Connect(hContext,NULL) ); TRY( Tspi_Context_GetTpmObject(hContext,&hTPM) ); for(i=1; i<argc; i++) { int pcrIndex = atoi(argv[i]); TRY( Tspi_TPM_PcrRead(hTPM,pcrIndex,&pcrlen,&pcrval) ); unsignedchararray2hex(pcrval, pcrlen, hexbuf); printf("%2d %s\n", pcrIndex, hexbuf); TRY( Tspi_Context_FreeMemory(hContext,pcrval) ); } Tspi_Context_Close(hContext); return 0; } 49 extendpcr.c /* * extendpcr - extends the current value of the selected PCR with the specified data * * Copyright (c) 2013 Jonathan Buhacoff * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include <stdio.h> <string.h> <trousers/tss.h> <tss/tcs.h> <tss/tspi.h> <tss/platform.h> <tss/tss_typedef.h> <tss/tss_structs.h> <tss/tpm.h> "hex.h" "config.h" // this macro assumes the following variable declarations are in scope: // 1. TSS_HCONTEXT hContext // 2. TSS_RESULT result // how to use it: // TRY( Tspi_Context_Create(&hContext) ); #define TRY(a) \ result = a; \ if( result != TSS_SUCCESS ) { \ fprintf(stderr, "%s:%d error 0x%x (%s) from %s\n", __FILE__, __LINE__, \ result, Trspi_Error_String(result), #a); \ Tspi_Context_Close(hContext); \ exit(result); } void usage(char *argv0) { fprintf(stderr, "\t%s: show current state of selected PCRs\n" "\tusage: %s <pcrN> <filename>\n\n" "\tOptions:\n" "\tpcrN - a number between 0 and 23 inclusive\n", "\tfilename - absolute or relative path to file containing data to extend to pcrN\n", argv0, argv0); exit(-1); } 50 int main(int argc, char **argv) { TSS_HCONTEXT hContext; TSS_HTPM hTPM; TSS_HPOLICY hTPMPolicy; TSS_RESULT result; UINT32 pcrValueLength; BYTE* pcrValue; char* hexbuf; int i; int pcrIndex; char* dataFilename; if( argc < 3 ) { usage(argv[0]); exit(1); } TRY( Tspi_Context_Create(&hContext) ); TRY( Tspi_Context_Connect(hContext,NULL) ); TRY( Tspi_Context_GetTpmObject(hContext,&hTPM) ); /* // authenticate to the TPM... not needed for extending 0-16 and 23. not sure if it would even help for 17-22. TRY( Tspi_Context_CreateObject(hContext,TSS_OBJECT_TYPE_POLICY,TSS_POLICY_USAGE,&hTPMPolicy) ); TRY( Tspi_Policy_AssignToObject(hTPMPolicy,hTPM) ); char *ownerSecret = read_owner_secret("."); TRY( Tspi_Policy_SetSecret(hTPMPolicy,TSS_SECRET_MODE_PLAIN,strlen(ownerSecret),ownerSecret) ); */ pcrIndex = atoi(argv[1]); dataFilename = argv[2]; // read specified data from file struct bytearray content = read_binary_data(dataFilename); if( content.length > 20 ) { printf("Data is longer than 20 bytes. Use sha1sum to summarize it first."); exit(1); } hexbuf = malloc( (2*content.length) + 1 ); bytearray2hex(content, hexbuf); // extend selected PCR with specified data printf("Extending PCR %i with %u bytes:\n%s\n", pcrIndex, content.length, hexbuf); result = Tspi_TPM_PcrExtend(hTPM,pcrIndex,content.length,content.data,NULL,&pcrValueLength,&pcrVal ue); free(hexbuf); free_bytearray(content); Tspi_Context_Close(hContext); return 0; } 51 aikpublish.c /* * Copyright (c) 2009 Hal Finney * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * aikpublish.c * * Publish a data file containing AIK public key, EK certificate * and supporting certificates. * * Small modifications by Jonathan Buhacoff. * Original source available at http://www.privacyca.com/code.html * * Format of output file is 4 bytes of AIK public key blob length, * big-endian, followed by AIK public key blob; * 4 bytes of certs-length, big-endian, meaning the length of all * of the following certificates in the file, followed by the * certificates. * Each certificate is preceded by its 3-byte length. * Certs should be in order from EK cert, to cert signing the EK * cert, to cert signing that one, and so on. * Last cert should be signed by the VeriSign Trusted Platform Module * Root CA. (The self-signed Verisign certificate should not be * included.) * Note that this certificate format and ordering is analogous to that * used for SSL/TLS. * * Also outputs a second file containing the TPM_KEY blob for the * newly generated AIK. */ #include #include #include #include #include #include #include #include #include <stdio.h> <string.h> <memory.h> <trousers/tss.h> <openssl/x509.h> <sys/types.h> <sys/stat.h> <unistd.h> "config.h" #define CKERR if (result != TSS_SUCCESS) goto error 52 /* VeriSign Trusted Platform Module Root CA modulus */ /* (defined at end of file) */ static BYTE trustedRoot[256]; static int verifyCertChain (BYTE *rootMod, UINT32 rootModLen, UINT32 nCerts, BYTE *certs); // jbuhacoff: added VERIFY_TRUSTED_ROOT option to support skipping verification #define VERIFY_TRUSTED_ROOT 0 int main (int ac, char **av) { TSS_HCONTEXT hContext; TSS_HTPM hTPM; TSS_HKEY hSRK; TSS_HKEY hAIK; TSS_HKEY hPCA; TSS_HPOLICY hTPMPolicy; TSS_HPOLICY hSrkPolicy; TSS_HPOLICY hAIKPolicy; TSS_UUID SRK_UUID = TSS_UUID_SRK; BYTE srkSecret[] = TSS_WELL_KNOWN_SECRET; BYTE n[2048/8]; FILE *f_in; FILE *f_out; char *pass = NULL; char *ownerSecret = NULL; char *configPath = "."; UINT32 initFlags; BYTE *blob; UINT32 blobLen; BYTE *certBuf; UINT32 certBufLen; UINT32 certLen; UINT32 tt[1]; int nCerts; int i; int result; // replacing command-line password with location of password and auth files jbuhacoff 20120316 if ((ac<2) || ((0==strcmp(av[1],"-f")) ? (ac<6) : (ac<4))) { fprintf (stderr, "Usage: %s [-f /path/to/config] ekcertfile [certfiles ...] outpubfile outaikblobfile\n", av[0]); exit (1); } if (0 == strcmp(av[1], "-f")) { configPath = av[2]; for (i=3; i<ac; i++) av[i-2] = av[i]; ac -= 2; } ownerSecret = read_owner_secret(configPath); /* Read certificates into buffer, precede each by 3 byte length */ nCerts = ac - 3; certBufLen = 0; certBuf = malloc (1); for (i=0; i<nCerts; i++) { if ((f_in = fopen (av[i+1], "rb")) == NULL) { fprintf (stderr, "Unable to open file %s for input\n", av[i+1]); exit (1); } 53 fseek (f_in, 0, SEEK_END); certLen = ftell (f_in); fseek (f_in, 0, SEEK_SET); certBuf = realloc (certBuf, certBufLen + 3 + certLen); certBuf[certBufLen] = certLen >> 16; certBuf[certBufLen+1] = certLen >> 8; certBuf[certBufLen+2] = certLen; if (fread (certBuf+certBufLen+3, 1, certLen, f_in) != certLen) { fprintf (stderr, "Failed to read file %s\n", av[i+1]); exit (1); } if (certBuf[certBufLen+3] != 0x30) { fprintf (stderr, "Certificate file %s not in binary format\n", av[i+1]); exit (1); } fclose (f_in); certBufLen += 3 + certLen; } // jbuhacoff: added VERIFY_TRUSTED_ROOT to support skipping verification for test server if (VERIFY_TRUSTED_ROOT && verifyCertChain (trustedRoot, sizeof(trustedRoot), nCerts, certBuf) < 0) { fprintf (stderr, "Certificate chain is incorrect\n"); exit (1); } result = Tspi_Context_Create(&hContext); CKERR; result = Tspi_Context_Connect(hContext, NULL); CKERR; result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, SRK_UUID, &hSRK); CKERR; result = Tspi_GetPolicyObject (hSRK, TSS_POLICY_USAGE, &hSrkPolicy); CKERR; result = Tspi_Policy_SetSecret(hSrkPolicy, TSS_SECRET_MODE_SHA1, sizeof(srkSecret), srkSecret); CKERR; result = Tspi_Context_GetTpmObject (hContext, &hTPM); CKERR; result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &hTPMPolicy); CKERR; result = Tspi_Policy_AssignToObject(hTPMPolicy, hTPM); if( ownerSecret != NULL ) { result = Tspi_Policy_SetSecret (hTPMPolicy, TSS_SECRET_MODE_PLAIN, strlen(ownerSecret), ownerSecret); CKERR; // jbuhacoff: do not include null terminator in the secret } else { result = Tspi_Policy_SetSecret (hTPMPolicy, TSS_SECRET_MODE_POPUP, 0, NULL); CKERR; } /* Create dummy PCA key */ result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY, TSS_KEY_TYPE_LEGACY|TSS_KEY_SIZE_2048, &hPCA); CKERR; memset (n, 0xff, sizeof(n)); result = Tspi_SetAttribData (hPCA, TSS_TSPATTRIB_RSAKEY_INFO, TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, sizeof(n), n); CKERR; /* Create AIK object */ initFlags = TSS_KEY_TYPE_IDENTITY | TSS_KEY_SIZE_2048; if (pass) initFlags |= TSS_KEY_AUTHORIZATION; result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY, initFlags, &hAIK); CKERR; if (pass) { 54 result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &hAIKPolicy); CKERR; result = Tspi_Policy_AssignToObject(hAIKPolicy, hAIK); result = Tspi_Policy_SetSecret (hAIKPolicy, TSS_SECRET_MODE_PLAIN, strlen(pass), pass); CKERR; // jbuhacoff: do not include null terminator in the password } /* Generate new AIK */ if( ownerSecret == NULL ) { /* Work around a bug in Trousers 0.3.1 - remove this block when fixed */ /* Force POPUP to activate, it is being ignored */ BYTE *dummyblob1; UINT32 dummylen1; if (Tspi_TPM_OwnerGetSRKPubKey(hTPM, &dummylen1, &dummyblob1) == TSS_SUCCESS) { Tspi_Context_FreeMemory (hContext, dummyblob1); } } free(ownerSecret); result = Tspi_TPM_CollateIdentityRequest(hTPM, hSRK, hPCA, 0, "", hAIK, TSS_ALG_AES, &blobLen, &blob); CKERR; Tspi_Context_FreeMemory (hContext, blob); /* Output file with AIK pub key and certs, preceded by 4-byte lengths */ result = Tspi_GetAttribData (hAIK, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, &blobLen, &blob); CKERR; if ((f_out = fopen (av[ac-2], "wb")) == NULL) { fprintf (stderr, "Unable to open %s for output\n", av[ac-2]); exit (1); } tt[0] = htonl (blobLen); fwrite (tt, 1, sizeof(UINT32), f_out); fwrite (blob, 1, blobLen, f_out); Tspi_Context_FreeMemory (hContext, blob); tt[0] = htonl (certBufLen); fwrite (tt, 1, sizeof(UINT32), f_out); if (fwrite (certBuf, 1, certBufLen, f_out) != certBufLen) { fprintf (stderr, "Unable to write to %s\n", av[ac-2]); exit (1); } free (certBuf); fclose (f_out); /* Output file with AIK blob for future use */ result = Tspi_GetAttribData (hAIK, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB, &blobLen, &blob); CKERR; if ((f_out = fopen (av[ac-1], "wb")) == NULL) { fprintf (stderr, "Unable to open %s for output\n", av[ac-1]); exit (1); } if (fwrite (blob, 1, blobLen, f_out) != blobLen) { fprintf (stderr, "Unable to write to %s\n", av[ac-1]); exit (1); } fclose (f_out); Tspi_Context_FreeMemory (hContext, blob); printf ("Success!\n"); return 0; 55 error: printf ("Failure, error code: 0x%x\n", result); return 1; } /* Check a certificate chain based on a trusted modulus from some root. */ /* The trusted root should sign the last extra cert; that should sign */ /* the previous one, and so on. */ /* Each cert is preceded by a 3-byte length in big-endian format */ /* We don't need to check the BasicConstraints field, for 2 reasons. */ /* First, we have to trust TPM vendor certifications anyway. */ /* And second, the last cert is an EK cert, and the TPM won't let EKs sign */ /* Return 0 if OK, -1 otherwise */ static int verifyCertChain (BYTE *rootMod, UINT32 rootModLen, UINT32 nCerts, BYTE *certs) { X509 *tbsX509 = NULL; EVP_PKEY *pkey = NULL; RSA *rsa; BYTE *pCert; UINT32 certLen; int rslt = -1; int i, j; EVP_add_digest(EVP_sha1()); pkey = EVP_PKEY_new (); rsa = RSA_new (); rsa->n = BN_bin2bn (rootMod, rootModLen, rsa->n); rsa->e = BN_new(); BN_set_word (rsa->e, 0x10001); EVP_PKEY_assign_RSA (pkey, rsa); for (i=nCerts-1; i>=0; i--) { pCert = certs; for (j=0; j<i; j++) { certLen = (pCert[0]<<16) | (pCert[1]<<8) | pCert[2]; pCert += 3 + certLen; } certLen = (pCert[0]<<16) | (pCert[1]<<8) | pCert[2]; pCert += 3; tbsX509 = d2i_X509 (NULL, (unsigned char const **)&pCert, certLen); if (!tbsX509) goto done; if (X509_verify (tbsX509, pkey) != 1) goto done; if (i > 0) { EVP_PKEY_free (pkey); pkey = X509_get_pubkey(tbsX509); if (pkey == NULL) goto done; } X509_free (tbsX509); tbsX509 = NULL; } /* Success */ rslt = 0; done: if (pkey) EVP_PKEY_free (pkey); if (tbsX509) X509_free (tbsX509); return rslt; } 56 /* VeriSign Trusted Platform Module Root CA modulus */ static BYTE trustedRoot[256] = { 0xD9, 0x50, 0x6B, 0x40, 0xE8, 0x7B, 0x63, 0x55, 0x87, 0x73, 0x3C, 0x6D, 0xD4, 0x81, 0xA7, 0xAE, 0x50, 0x4A, 0x2A, 0xBD, 0x0A, 0xE8, 0xE6, 0x57, 0x56, 0x59, 0x6B, 0xE8, 0x5E, 0x6F, 0xB8, 0x5D, 0x25, 0x9D, 0xE6, 0xA3, 0x09, 0x1A, 0x71, 0x64, 0x95, 0x27, 0x7B, 0xBB, 0xFB, 0xFD, 0xAA, 0x71, 0x7A, 0xCA, 0xF9, 0xF4, 0xBA, 0xD0, 0x70, 0x36, 0xCE, 0x92, 0xD9, 0x6B, 0x19, 0x75, 0xF3, 0x39, 0x78, 0xCA, 0x05, 0xA5, 0xD9, 0x06, 0x42, 0x8E, 0x3B, 0xC4, 0x4E, 0x20, 0x4D, 0x80, 0x7B, 0xAA, 0xEC, 0x94, 0xE3, 0x32, 0x9E, 0x53, 0xC7, 0x58, 0xFE, 0x07, 0x29, 0xDA, 0x20, 0x65, 0xED, 0xCB, 0x3C, 0xF5, 0x62, 0xB8, 0x2D, 0x78, 0xBA, 0x18, 0x33, 0xE6, 0x25, 0xC9, 0xF2, 0x91, 0x5F, 0x51, 0x07, 0x4A, 0xC4, 0x27, 0x4A, 0x59, 0x3C, 0xC8, 0x0A, 0x0D, 0x01, 0xFA, 0x5E, 0x3A, 0xA6, 0x9E, 0x36, 0x17, 0x1A, 0xFC, 0xDD, 0xE4, 0x7B, 0xD8, 0xEF, 0x64, 0x4B, 0x31, 0x2A, 0x8A, 0x39, 0x1A, 0x61, 0xDA, 0x03, 0xC7, 0x4E, 0xB2, 0xC5, 0x60, 0x0B, 0x82, 0xE5, 0x06, 0xCD, 0x2E, 0xC7, 0xE6, 0xCC, 0x9C, 0x9E, 0xED, 0xAD, 0x00, 0x60, 0xC6, 0x16, 0xB9, 0xAC, 0x42, 0x88, 0x7C, 0x98, 0xAE, 0x05, 0x52, 0x2E, 0x6F, 0x71, 0xEF, 0x09, 0xB9, 0x6B, 0xA1, 0x8A, 0xB0, 0x97, 0x67, 0x39, 0x8F, 0xFD, 0xF5, 0x78, 0xB5, 0x89, 0xDD, 0xC3, 0xE1, 0xC9, 0x4B, 0xF0, 0xFB, 0x5E, 0xE5, 0xA4, 0x05, 0x67, 0x1B, 0x9B, 0x47, 0x25, 0x2D, 0x36, 0xE6, 0x61, 0x9E, 0xC0, 0x7B, 0x5A, 0xE5, 0xD5, 0x74, 0xCF, 0xE6, 0x97, 0x7C, 0x43, 0x77, 0x07, 0x18, 0x1E, 0x91, 0xD0, 0x77, 0x17, 0xC8, 0x00, 0xB2, 0x13, 0x85, 0x63, 0xA7, 0xF8, 0x34, 0x27, 0x71, 0xC9, 0x8C, 0x77, 0x77, 0x2F, 0xA4, 0xEB, 0xC3, }; 57 aikchallenge.c /* * Copyright (c) 2009 Hal Finney * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * Small modifications by Jonathan Buhacoff. * Original source available at http://www.privacyca.com/code.html * * Challenge a claimed AIK public key and EK certificate * This encrypts a specified string to the Endorsement Key, which will only * decrypt it if the corresponding AIK is legitimate. * Also checks that EK cert is valid and rooted at trusted Verisign cert * * */ #include <stdio.h> #include <string.h> #include <memory.h> #include <openssl/x509.h> // VERIFY_TRUSTED_ROOT: support skipping the trusted root verification for test systems that do not have a complete certificate chain. -jbuhacoff // must be 1 for enabled or 0 for disabled #define VERIFY_TRUSTED_ROOT 0 #define TPM_ALG_AES #define TPM_ES_SYM_CBC_PKCS5PAD #define TPM_SS_NONE #ifndef BYTE #define BYTE unsigned char #endif #ifndef UINT16 #define UINT16 unsigned short #endif #ifndef UINT32 #define UINT32 unsigned #endif 0x00000006 ((UINT16)0x00ff) ((UINT16)0x0001) 58 /* VeriSign Trusted Platform Module Root CA modulus */ /* (defined at end of file) */ static BYTE trustedRoot[256]; static int verifyCertChain (BYTE *rootMod, UINT32 rootModLen, UINT32 nCerts, BYTE *certs); int main (int ac, char **av) { FILE *f_in; FILE *f_out; UINT32 proofLen; BYTE *proof; BYTE *pub; UINT32 pubLen; BYTE *certs; UINT32 certsLen; UINT32 certLen; BYTE key[128/8]; BYTE iv[16]; BYTE asymPlain[8 + sizeof(key) + SHA_DIGEST_LENGTH]; unsigned char oaepPad[4] = "TCPA"; BYTE *asymPadded; UINT32 asymPaddedLength; BYTE *asymEnc; UINT32 asymEncLength; BYTE *chal; UINT32 chalLen; BYTE *symEnc; UINT32 symEncLength; BYTE *symAttest; UINT32 symAttestLength; EVP_CIPHER_CTX ctx; X509 *ekX509; X509_NAME *ekSubj; EVP_PKEY *ekPkey; RSA *ekRsa; RSA *aikRsa; UINT32 tt[1]; int trousersIVMode = 1; int out1, out2; int nCerts; int result; if (ac != 5) { fprintf (stderr, "Usage: %s secretfile aikprooffile outchallengefile outrsafile\n", av[0]); exit (1); } /* Read challenge */ if ((f_in = fopen (av[1], "rb")) == NULL) { fprintf (stderr, "Unable to open file %s\n", av[1]); exit (1); } fseek (f_in, 0, SEEK_END); chalLen = ftell (f_in); fseek (f_in, 0, SEEK_SET); chal = malloc (chalLen); if (fread (chal, 1, chalLen, f_in) != chalLen) { fprintf (stderr, "Unable to read file %s\n", av[1]); exit (1); } fclose (f_in); 59 /* Read AIK proof */ if ((f_in = fopen (av[2], "rb")) == NULL) { fprintf (stderr, "Unable to open file %s\n", av[2]); exit (1); } fseek (f_in, 0, SEEK_END); proofLen = ftell (f_in); fseek (f_in, 0, SEEK_SET); proof = malloc (proofLen); if (fread (proof, 1, proofLen, f_in) != proofLen) { fprintf (stderr, "Unable to read file %s\n", av[2]); exit (1); } fclose (f_in); if (proofLen < 3) goto badproof; pubLen = ntohl (*(UINT32*)proof); if (pubLen + 4 + 4 > proofLen) goto badproof; pub = proof + 4; proof += pubLen+4; proofLen -= pubLen+4; certsLen = ntohl (*(UINT32*)proof); if (certsLen + 4 != proofLen) goto badproof; proof += 4; certs = proof; nCerts = 0; for ( ; ; ) { ++nCerts; if (certsLen < 3) goto badproof; certLen = (proof[0]<<16) | (proof[1]<<8) | proof[2]; if (certLen + 3 > certsLen) goto badproof; proof += certLen + 3; certsLen -= certLen + 3; if (certsLen == 0) break; } // VERIFY_TRUSTED_ROOT: support skipping the trusted root verification for test systems that do not have a complete certificate chain. -jbuhacoff if (VERIFY_TRUSTED_ROOT && verifyCertChain (trustedRoot, sizeof(trustedRoot), nCerts, certs) != 0) { fprintf (stderr, "Unable to validate certificate chain in proof file\n"); exit (1); } /* Pull endorsement key from 1st cert */ certLen = (certs[0]<<16) | (certs[1]<<8) | certs[2]; certs += 3; if ((ekX509 = d2i_X509 (NULL, (unsigned char const **)&certs, certLen)) == NULL) goto badproof; /* One last check: EK certs must have empty subject fields */ if ((ekSubj = X509_get_subject_name (ekX509)) == NULL) goto badproof; if (X509_NAME_entry_count (ekSubj) != 0) goto badproof; /* OpenSSL can't parse EK key due to OAEP OID - fix it */ { X509_PUBKEY *pk = X509_get_X509_PUBKEY(ekX509); 60 int algbufLen = i2d_X509_ALGOR(pk->algor, NULL); unsigned char *algbuf = malloc(algbufLen); unsigned char *algbufPtr = algbuf; i2d_X509_ALGOR(pk->algor, &algbufPtr); if (algbuf[12] == 7) algbuf[12] = 1; algbufPtr = algbuf; d2i_X509_ALGOR(&pk->algor, (void *)&algbufPtr, algbufLen); free (algbuf); } if ((ekPkey = X509_get_pubkey (ekX509)) == NULL) goto badproof; if ((ekRsa = EVP_PKEY_get1_RSA (ekPkey)) == NULL) goto badproof; /* Construct encrypted output challenge */ RAND_bytes (key, sizeof(key)); RAND_bytes (iv, sizeof(iv)); /* Prepare buffer to be RSA encrypted to endorsement key */ ((UINT32 *)asymPlain)[0] = htonl(TPM_ALG_AES); ((UINT16 *)asymPlain)[2] = htons(TPM_ES_SYM_CBC_PKCS5PAD); ((UINT16 *)asymPlain)[3] = htons(sizeof(key)); memcpy (asymPlain+8, key, sizeof(key)); SHA1 (pub, pubLen, asymPlain + 8 + sizeof(key)); /* Encrypt to EK */ /* Must use custom padding for TPM to decrypt it */ asymPaddedLength = asymEncLength = RSA_size (ekRsa); asymPadded = malloc (asymPaddedLength); asymEnc = malloc (asymEncLength); RSA_padding_add_PKCS1_OAEP(asymPadded, asymPaddedLength, asymPlain, sizeof(asymPlain), oaepPad, sizeof(oaepPad)); RSA_public_encrypt (asymPaddedLength, asymPadded, asymEnc, ekRsa, RSA_NO_PADDING); free (asymPadded); asymPadded = NULL; /* Encrypt challenge with key */ symEnc = malloc (chalLen + sizeof(iv)); EVP_CIPHER_CTX_init (&ctx); EVP_EncryptInit(&ctx, EVP_aes_128_cbc(), key, iv); EVP_EncryptUpdate (&ctx, symEnc, &out1, chal, chalLen); EVP_EncryptFinal_ex (&ctx, symEnc+out1, &out2); EVP_CIPHER_CTX_cleanup(&ctx); symEncLength = out1 + out2; /* Create TPM_SYM_CA_ATTESTATION struct to hold encrypted cert */ symAttestLength = 28 + sizeof(iv) + symEncLength; symAttest = malloc (symAttestLength); ((UINT32 *)symAttest)[0] = htonl(symEncLength); ((UINT32 *)symAttest)[1] = htonl(TPM_ALG_AES); ((UINT16 *)symAttest)[4] = htons(TPM_ES_SYM_CBC_PKCS5PAD); ((UINT16 *)symAttest)[5] = htons(TPM_SS_NONE); ((UINT32 *)symAttest)[3] = htonl(12+sizeof(iv)); ((UINT32 *)symAttest)[4] = htonl(128); /* Key length in bits */ ((UINT32 *)symAttest)[5] = htonl(sizeof(iv)); /* Block size in bytes */ ((UINT32 *)symAttest)[6] = htonl(sizeof(iv)); /* IV size in bytes */ memcpy (symAttest+28, iv, sizeof(iv)); memcpy (symAttest+28+sizeof(iv), symEnc, symEncLength); if (trousersIVMode) { ((UINT32 *)symAttest)[0] = htonl(symEncLength + sizeof(iv)); ((UINT32 *)symAttest)[3] = htonl(12); /* Take IV to be start of symEnc */ ((UINT32 *)symAttest)[6] = htonl(0); /* IV size in bytes */ } free (symEnc); 61 symEnc = NULL; if ((f_out = fopen (av[3], "wb")) == NULL) { fprintf (stderr, "Unable to open file %s for output\n", av[3]); exit (1); } /* Precede the two blocks with 4-byte lengths */ tt[0] = htonl (asymEncLength); fwrite (tt, 1, sizeof(UINT32), f_out); fwrite (asymEnc, 1, asymEncLength, f_out); tt[0] = htonl (symAttestLength); fwrite (tt, 1, sizeof(UINT32), f_out); if (fwrite (symAttest, 1, symAttestLength, f_out) != symAttestLength) { fprintf (stderr, "Unable to write to file %s\n", av[3]); exit (1); } fclose (f_out); /* Output RSA key representing the AIK for future use */ if ((f_out = fopen (av[4], "wb")) == NULL) { fprintf (stderr, "Unable to open file %s for output\n", av[4]); exit (1); } aikRsa = RSA_new(); aikRsa->n = BN_bin2bn (pub+pubLen-256, 256, NULL); aikRsa->e = BN_new(); BN_set_word (aikRsa->e, 0x10001); if (PEM_write_RSA_PUBKEY(f_out, aikRsa) < 0) { fprintf (stderr, "Unable to write to file %s\n", av[3]); exit (1); } fclose (f_out); printf ("Success!\n"); return 0; badproof: fprintf (stderr, "Input AIK proof file incorrect format\n"); return 1; } /* Check a certificate chain based on a trusted modulus from some root. */ /* The trusted root should sign the last extra cert; that should sign */ /* the previous one, and so on. */ /* Each cert is preceded by a 3-byte length in big-endian format */ /* We don't need to check the BasicConstraints field, for 2 reasons. */ /* First, we have to trust TPM vendor certifications anyway. */ /* And second, the last cert is an EK cert, and the TPM won't let EKs sign */ /* Return 0 if OK, -1 otherwise */ static int verifyCertChain (BYTE *rootMod, UINT32 rootModLen, UINT32 nCerts, BYTE *certs) { X509 *tbsX509 = NULL; EVP_PKEY *pkey = NULL; RSA *rsa; BYTE *pCert; UINT32 certLen; int rslt = -1; int i, j; EVP_add_digest(EVP_sha1()); pkey = EVP_PKEY_new (); rsa = RSA_new (); rsa->n = BN_bin2bn (rootMod, rootModLen, rsa->n); 62 rsa->e = BN_new(); BN_set_word (rsa->e, 0x10001); EVP_PKEY_assign_RSA (pkey, rsa); for (i=nCerts-1; i>=0; i--) { pCert = certs; for (j=0; j<i; j++) { certLen = (pCert[0]<<16) | (pCert[1]<<8) | pCert[2]; pCert += 3 + certLen; } certLen = (pCert[0]<<16) | (pCert[1]<<8) | pCert[2]; pCert += 3; tbsX509 = d2i_X509 (NULL, (unsigned char const **)&pCert, certLen); if (!tbsX509) goto done; if (X509_verify (tbsX509, pkey) != 1) goto done; if (i > 0) { EVP_PKEY_free (pkey); pkey = X509_get_pubkey(tbsX509); if (pkey == NULL) goto done; } X509_free (tbsX509); tbsX509 = NULL; } /* Success */ rslt = 0; done: if (pkey) EVP_PKEY_free (pkey); if (tbsX509) X509_free (tbsX509); return rslt; } /* VeriSign Trusted Platform Module Root CA modulus */ static BYTE trustedRoot[256] = { 0xD9, 0x50, 0x6B, 0x40, 0xE8, 0x7B, 0x63, 0x55, 0x87, 0x73, 0x3C, 0x6D, 0xD4, 0x81, 0xA7, 0xAE, 0x50, 0x4A, 0x2A, 0xBD, 0x0A, 0xE8, 0xE6, 0x57, 0x56, 0x59, 0x6B, 0xE8, 0x5E, 0x6F, 0xB8, 0x5D, 0x25, 0x9D, 0xE6, 0xA3, 0x09, 0x1A, 0x71, 0x64, 0x95, 0x27, 0x7B, 0xBB, 0xFB, 0xFD, 0xAA, 0x71, 0x7A, 0xCA, 0xF9, 0xF4, 0xBA, 0xD0, 0x70, 0x36, 0xCE, 0x92, 0xD9, 0x6B, 0x19, 0x75, 0xF3, 0x39, 0x78, 0xCA, 0x05, 0xA5, 0xD9, 0x06, 0x42, 0x8E, 0x3B, 0xC4, 0x4E, 0x20, 0x4D, 0x80, 0x7B, 0xAA, 0xEC, 0x94, 0xE3, 0x32, 0x9E, 0x53, 0xC7, 0x58, 0xFE, 0x07, 0x29, 0xDA, 0x20, 0x65, 0xED, 0xCB, 0x3C, 0xF5, 0x62, 0xB8, 0x2D, 0x78, 0xBA, 0x18, 0x33, 0xE6, 0x25, 0xC9, 0xF2, 0x91, 0x5F, 0x51, 0x07, 0x4A, 0xC4, 0x27, 0x4A, 0x59, 0x3C, 0xC8, 0x0A, 0x0D, 0x01, 0xFA, 0x5E, 0x3A, 0xA6, 0x9E, 0x36, 0x17, 0x1A, 0xFC, 0xDD, 0xE4, 0x7B, 0xD8, 0xEF, 0x64, 0x4B, 0x31, 0x2A, 0x8A, 0x39, 0x1A, 0x61, 0xDA, 0x03, 0xC7, 0x4E, 0xB2, 0xC5, 0x60, 0x0B, 0x82, 0xE5, 0x06, 0xCD, 0x2E, 0xC7, 0xE6, 0xCC, 0x9C, 0x9E, 0xED, 0xAD, 0x00, 0x60, 0xC6, 0x16, 0xB9, 0xAC, 0x42, 0x88, 0x7C, 0x98, 0xAE, 0x05, 0x52, 0x2E, 0x6F, 0x71, 0xEF, 0x09, 0xB9, 0x6B, 0xA1, 0x8A, 0xB0, 0x97, 0x67, 0x39, 0x8F, 0xFD, 0xF5, 0x78, 0xB5, 0x89, 0xDD, 0xC3, 0xE1, 0xC9, 0x4B, 0xF0, 0xFB, 0x5E, 0xE5, 0xA4, 0x05, 0x67, 0x1B, 0x9B, 0x47, 0x25, 0x2D, 0x36, 0xE6, 63 0x61, 0xCF, 0x1E, 0x13, 0xC9, }; 0x9E, 0xE6, 0x91, 0x85, 0x8C, 0xC0, 0x97, 0xD0, 0x63, 0x77, 0x7B, 0x7C, 0x77, 0xA7, 0x77, 0x5A, 0x43, 0x17, 0xF8, 0x2F, 0xE5, 0x77, 0xC8, 0x34, 0xA4, 0xD5, 0x07, 0x00, 0x27, 0xEB, 0x74, 0x18, 0xB2, 0x71, 0xC3, 64 aikrespond.c /* * Copyright (c) 2009 Hal Finney * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * aikrespond.c * * Third step in proving an AIK is valid without using a Privacy CA. * * Reads AIK blob file and challenge file from challenger. Decrypts * encrypted data and outputs to a file, which should be sent back to * challenger. Successful decryption proves that it is a real AIK. * * Small modifications by Jonathan Buhacoff * Original source available at http://www.privacyca.com/code.html * */ #include #include #include #include #include <stdio.h> <string.h> <memory.h> <trousers/tss.h> "config.h" #define CKERR if (result != TSS_SUCCESS) goto error int main (int ac, char **av) { TSS_HCONTEXT hContext; TSS_HTPM hTPM; TSS_HKEY hSRK; TSS_HKEY hAIK; TSS_HPOLICY hTPMPolicy; TSS_HPOLICY hSrkPolicy; TSS_HPOLICY hAIKPolicy; TSS_UUID SRK_UUID = TSS_UUID_SRK; BYTE srkSecret[] = TSS_WELL_KNOWN_SECRET; FILE *f_in; FILE *f_out; char *pass = NULL; char *ownerSecret = NULL; BYTE *response; UINT32 responseLen; 65 BYTE UINT32 BYTE UINT32 BYTE UINT32 int int *buf; bufLen; *asym; asymLen; *sym; symLen; i; result; if ((ac<2) || ((0==strcmp(av[1],"-p")) ? (ac!=6) : (ac!=4))) { fprintf (stderr, "Usage: %s [-p password] aikblobfile challengefile outresponsefile\n", av[0]); exit (1); } if (0 == strcmp(av[1], "-p")) { pass = av[2]; for (i=3; i<ac; i++) av[i-2] = av[i]; ac -= 2; } ownerSecret = read_owner_secret("."); result = Tspi_Context_Create(&hContext); CKERR; result = Tspi_Context_Connect(hContext, NULL); CKERR; result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, SRK_UUID, &hSRK); CKERR; result = Tspi_GetPolicyObject (hSRK, TSS_POLICY_USAGE, &hSrkPolicy); CKERR; result = Tspi_Policy_SetSecret(hSrkPolicy, TSS_SECRET_MODE_SHA1, sizeof(srkSecret), srkSecret); CKERR; result = Tspi_Context_GetTpmObject (hContext, &hTPM); CKERR; result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &hTPMPolicy); CKERR; result = Tspi_Policy_AssignToObject(hTPMPolicy, hTPM); if( ownerSecret != NULL ) { result = Tspi_Policy_SetSecret (hTPMPolicy, TSS_SECRET_MODE_PLAIN, strlen(ownerSecret), ownerSecret); CKERR; // jbuhacoff: do not include null terminator in password } else { result = Tspi_Policy_SetSecret (hTPMPolicy, TSS_SECRET_MODE_POPUP, 0, NULL); CKERR; } /* Read AIK blob */ if ((f_in = fopen(av[1], "rb")) == NULL) { fprintf (stderr, "Unable to open file %s\n", av[1]); exit (1); } fseek (f_in, 0, SEEK_END); bufLen = ftell (f_in); fseek (f_in, 0, SEEK_SET); buf = malloc (bufLen); if (fread(buf, 1, bufLen, f_in) != bufLen) { fprintf (stderr, "Unable to readn file %s\n", av[1]); exit (1); } fclose (f_in); result = Tspi_Context_LoadKeyByBlob (hContext, hSRK, bufLen, buf, &hAIK); CKERR; free (buf); if (pass) { result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &hAIKPolicy); CKERR; result = Tspi_Policy_AssignToObject(hAIKPolicy, hAIK); 66 result = Tspi_Policy_SetSecret (hAIKPolicy, TSS_SECRET_MODE_PLAIN, strlen(pass), pass); CKERR; // jbuhacoff: do not include null terminator in secret } /* Read challenge file */ if ((f_in = fopen(av[2], "rb")) == NULL) { fprintf (stderr, "Unable to open file %s\n", av[2]); exit (1); } fseek (f_in, 0, SEEK_END); bufLen = ftell (f_in); fseek (f_in, 0, SEEK_SET); buf = malloc (bufLen); if (fread(buf, 1, bufLen, f_in) != bufLen) { fprintf (stderr, "Unable to readn file %s\n", av[2]); exit (1); } fclose (f_in); /* Parse challenge */ if (bufLen < 8) goto badchal; asymLen = ntohl(*(UINT32*)buf); asym = buf + 4; buf += asymLen + 4; if (bufLen < asymLen+8) goto badchal; symLen = ntohl(*(UINT32*)buf); if (bufLen != asymLen + symLen + 8) goto badchal; sym = buf + 4; /* Decrypt challenge data */ if( ownerSecret == NULL ) { /* Work around a bug in Trousers 0.3.1 - remove this block when fixed */ /* Force POPUP to activate, it is being ignored */ BYTE *dummyblob1; UINT32 dummylen1; if (Tspi_TPM_OwnerGetSRKPubKey(hTPM, &dummylen1, &dummyblob1) == TSS_SUCCESS) { Tspi_Context_FreeMemory (hContext, dummyblob1); } } result = Tspi_TPM_ActivateIdentity (hTPM, hAIK, asymLen, asym, symLen, sym, &responseLen, &response); CKERR; /* Output response file */ if ((f_out = fopen (av[3], "wb")) == NULL) { fprintf (stderr, "Unable to create file %s\n", av[3]); exit (1); } if (fwrite (response, 1, responseLen, f_out) != responseLen) { fprintf (stderr, "Unable to write to file %s\n", av[3]); exit (1); } fclose (f_out); printf ("Success!\n"); return 0; error: fprintf (stderr, "Failure, error code: 0x%x\n", result); return 1; 67 badchal: fprintf (stderr, "Challenge file format is wrong\n"); return 1; } 68 aikquote.c /* * Copyright (c) 2009 Hal Finney * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * aikquote.c * * Produce a PCR quote using an AIK. * * PCRs are specified on command line. Nonce is fixed at 0 for now. * * The format of the quote file output is as follows: * 2 bytes of PCR bitmask length (big-endian) * PCR bitmask (LSB of 1st byte is PCR0, MSB is PCR7; LSB of 2nd byte is PCR8, etc) * 4 bytes of PCR value length (20 times number of PCRs) (big-endian) * PCR values * 256 bytes of Quote signature * * Note that the 1st portion is the serialized TPM_PCR_SELECTION that gets hashed. * * Takes an optional challenge file to be hashed as the externalData input * to the Quote. This would typically be supplied by the challenger to prevent * replay of old Quote output. If no file is specified the challenge is zeros. * * Small modifications by Jonathan Buhacoff * Original source available at http://www.privacyca.com/code.html * */ #include #include #include #include #include <stdio.h> <string.h> <memory.h> <trousers/tss.h> "config.h" #define CKERR(x) if (result != TSS_SUCCESS) { printf("Error: "); printf((x)); printf("\n"); goto error; } static void sha1(TSS_HCONTEXT hContext, void *buf, UINT32 bufLen, BYTE *digest); int main (int ac, char **av) 69 { TSS_HCONTEXT TSS_HTPM TSS_HKEY TSS_HKEY TSS_HPOLICY TSS_HPOLICY TSS_HPCRS TSS_UUID TSS_VALIDATION TPM_QUOTE_INFO BYTE FILE FILE char char char UINT32 UINT32 UINT32 UINT32 BYTE UINT32 BYTE BYTE UINT32 BYTE BYTE int int hContext; hTPM; hSRK; hAIK; hSrkPolicy; hAIKPolicy; hPCRs; SRK_UUID = TSS_UUID_SRK; valid; *quoteInfo; srkSecret[] = TSS_WELL_KNOWN_SECRET; *f_in; *f_out; *chalfile = NULL; *pass = NULL; *ownerSecret = NULL; tpmProp; npcrMax; npcrBytes; npcrs = 0; *buf; bufLen; *bp; *tmpbuf; tmpbufLen; chalmd[20]; pcrmd[20]; i; result; while (ac > 3) { if (0 == strcmp(av[1], "-p")) { pass = av[2]; for (i=3; i<ac; i++) av[i-2] = av[i]; ac -= 2; } else if (0 == strcmp(av[1], "-c")) { chalfile = av[2]; for (i=3; i<ac; i++) av[i-2] = av[i]; ac -= 2; } else break; } if (ac < 4) { fprintf (stderr, "Usage: %s [-p password] [-c challengefile] aikblobfile pcrnumber [pcrnumber] outquotefile\n", av[0]); exit (1); } ownerSecret = read_owner_secret("."); result = Tspi_Context_Create(&hContext); CKERR("Tspi_Context_Create"); result = Tspi_Context_Connect(hContext, NULL); CKERR("Tspi_Context_Connect"); result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, SRK_UUID, &hSRK); CKERR("Tspi_Context_LoadKeyByUUID(srk)"); result = Tspi_GetPolicyObject (hSRK, TSS_POLICY_USAGE, &hSrkPolicy); CKERR("Tspi_GetPolicyObject(srk)"); result = Tspi_Policy_SetSecret(hSrkPolicy, TSS_SECRET_MODE_SHA1, sizeof(srkSecret), srkSecret); CKERR("Tspi_Policy_SetSecret(srk)"); result = Tspi_Context_GetTpmObject (hContext, &hTPM); CKERR("Tspi_Context_GetTpmObject"); 70 /* Hash challenge file if present */ if (chalfile) { if ((f_in = fopen(chalfile, "rb")) == NULL) { fprintf (stderr, "Unable to open file %s\n", chalfile); exit (1); } fseek (f_in, 0, SEEK_END); bufLen = ftell (f_in); fseek (f_in, 0, SEEK_SET); buf = malloc (bufLen); if (fread(buf, 1, bufLen, f_in) != bufLen) { fprintf (stderr, "Unable to readn file %s\n", chalfile); exit (1); } fclose (f_in); sha1 (hContext, buf, bufLen, chalmd); free (buf); } else { memset (chalmd, 0, sizeof(chalmd)); } /* Read AIK blob */ if ((f_in = fopen(av[1], "rb")) == NULL) { fprintf (stderr, "Unable to open file %s\n", av[1]); exit (1); } fseek (f_in, 0, SEEK_END); bufLen = ftell (f_in); fseek (f_in, 0, SEEK_SET); buf = malloc (bufLen); if (fread(buf, 1, bufLen, f_in) != bufLen) { fprintf (stderr, "Unable to readn file %s\n", av[1]); exit (1); } fclose (f_in); result = Tspi_Context_LoadKeyByBlob (hContext, hSRK, bufLen, buf, &hAIK); CKERR("Tspi_Context_LoadKeyByBlob(aik)"); free (buf); if( ownerSecret != NULL ) { result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &hAIKPolicy); CKERR("Tspi_Context_CreateObject(aik)"); result = Tspi_Policy_AssignToObject(hAIKPolicy, hAIK); result = Tspi_Policy_SetSecret (hAIKPolicy, TSS_SECRET_MODE_PLAIN, strlen(ownerSecret), ownerSecret); CKERR("Tspi_Policy_SetSecret(aik)"); // jbuhacoff: do not include null terminator in password } /* Create PCR list to be quoted */ tpmProp = TSS_TPMCAP_PROP_PCR; result = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_PROPERTY, sizeof(tpmProp), (BYTE *)&tpmProp, &tmpbufLen, &tmpbuf); CKERR("Tspi_TPM_GetCapability"); npcrMax = *(UINT32 *)tmpbuf; Tspi_Context_FreeMemory(hContext, tmpbuf); npcrBytes = (npcrMax + 7) / 8; result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS, TSS_PCRS_STRUCT_INFO, &hPCRs); CKERR("Tspi_Context_CreateObject(pcrs)"); /* Also PCR buffer */ buf = malloc (2 + npcrBytes + 4 + 20 * npcrMax); *(UINT16 *)buf = htons(npcrBytes); for (i=0; i<npcrBytes; i++) 71 buf[2+i] = 0; for (i=2; i<ac-1; i++) { char *endptr; long pcr = strtol (av[i], &endptr, 10); if (pcr < 0 || pcr > npcrMax || *av[i] == 0 || *endptr != 0) { fprintf (stderr, "Illegal PCR value %s\n", av[i]); exit (1); } result = Tspi_PcrComposite_SelectPcrIndex(hPCRs, pcr); CKERR("Tspi_PcrComposite_SelectPcrIndex"); ++npcrs; buf[2+(pcr/8)] |= 1 << (pcr%8); } /* Create TSS_VALIDATION struct for Quote */ valid.ulExternalDataLength = sizeof(chalmd); valid.rgbExternalData = chalmd; /* Perform Quote */ result = Tspi_TPM_Quote(hTPM, hAIK, hPCRs, &valid); CKERR("Tspi_TPM_Quote"); quoteInfo = (TPM_QUOTE_INFO *)valid.rgbData; /* Fill in rest of PCR buffer */ bp = buf + 2 + npcrBytes; *(UINT32 *)bp = htonl (20*npcrs); bp += sizeof(UINT32); for (i=0; i<npcrMax; i++) { if (buf[2+(i/8)] & (1 << (i%8))) { result = Tspi_PcrComposite_GetPcrValue(hPCRs, i, &tmpbufLen, &tmpbuf); CKERR("Tspi_PcrComposite_GetPcrValue"); memcpy (bp, tmpbuf, tmpbufLen); bp += tmpbufLen; Tspi_Context_FreeMemory(hContext, tmpbuf); } } bufLen = bp - buf; /* Test the hash */ sha1 (hContext, buf, bufLen, pcrmd); if (memcmp (pcrmd, quoteInfo->compositeHash.digest, sizeof(pcrmd)) != 0) { /* Try with smaller digest length */ *(UINT16 *)buf = htons(npcrBytes-1); memmove (buf+2+npcrBytes-1, buf+2+npcrBytes, bufLen-2-npcrBytes); bufLen -= 1; sha1 (hContext, buf, bufLen, pcrmd); if (memcmp (pcrmd, quoteInfo->compositeHash.digest, sizeof(pcrmd)) != 0) { fprintf (stderr, "Inconsistent PCR hash in output of quote\n"); exit (1); } } Tspi_Context_FreeMemory(hContext, tmpbuf); /* Create output file */ if ((f_out = fopen (av[ac-1], "wb")) == NULL) { fprintf (stderr, "Unable to create file %s\n", av[ac-1]); exit (1); } if (fwrite (buf, 1, bufLen, f_out) != bufLen) { fprintf (stderr, "Unable to write to file %s\n", av[ac-1]); exit (1); } if (fwrite (valid.rgbValidationData, 1, valid.ulValidationDataLength, f_out) != valid.ulValidationDataLength) { 72 fprintf (stderr, "Unable to write to file %s\n", av[ac-1]); exit (1); } fclose (f_out); free(ownerSecret); printf ("Success!\n"); return 0; error: fprintf (stderr, "Failure, error code: 0x%x\n", result); return 1; } static void sha1(TSS_HCONTEXT hContext, void *buf, UINT32 bufLen, BYTE *digest) { TSS_HHASH hHash; BYTE *tmpbuf; UINT32 tmpbufLen; Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_HASH, TSS_HASH_DEFAULT, &hHash); Tspi_Hash_UpdateHashValue(hHash, bufLen, (BYTE *)buf); Tspi_Hash_GetHashValue(hHash, &tmpbufLen, &tmpbuf); memcpy (digest, tmpbuf, tmpbufLen); Tspi_Context_FreeMemory(hContext, tmpbuf); Tspi_Context_CloseObject(hContext, hHash); } 73 aikqverify.c /* Verify a quote issued by an AIK */ /* See aikquote.c for format of quote data file */ /* Source code available at http://www.privacyca.com/code.html */ /* * Copyright (c) 2009 Hal Finney * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include <stdio.h> #include <string.h> #include <memory.h> //#include <trousers/tss.h> #include <openssl/pem.h> #include <openssl/x509.h> #include <openssl/sha.h> #ifndef BYTE #define BYTE unsigned char #endif #ifndef UINT16 #define UINT16 unsigned short #endif #ifndef UINT32 #define UINT32 unsigned #endif int main (int ac, char **av) { FILE *f_in; BYTE *chal; UINT32 chalLen; BYTE *quote; UINT32 quoteLen; RSA *aikRsa; UINT32 selectLen; BYTE *select; UINT32 pcrLen; BYTE *pcrs; UINT32 sigLen; BYTE *sig; 74 BYTE BYTE BYTE char int int int chalmd[20]; md[20]; qinfo[8+20+20]; *chalfile = NULL; pcr; pcri = 0; i; if (ac == 5 && 0 == strcmp(av[1], "-c")) { chalfile = av[2]; for (i=3; i<ac; i++) av[i-2] = av[i]; ac -= 2; } if (ac != 3) { fprintf (stderr, "Usage: %s [-c challengefile] aikrsafile quotefile\n", av[0]); exit (1); } /* Read challenge file */ if (chalfile) { if ((f_in = fopen (chalfile, "rb")) == NULL) { fprintf (stderr, "Unable to open file %s\n", chalfile); exit (1); } fseek (f_in, 0, SEEK_END); chalLen = ftell (f_in); fseek (f_in, 0, SEEK_SET); chal = malloc (chalLen); if (fread (chal, 1, chalLen, f_in) != chalLen) { fprintf (stderr, "Unable to read file %s\n", chalfile); exit (1); } fclose (f_in); SHA1 (chal, chalLen, chalmd); free (chal); } else { memset (chalmd, 0, sizeof(chalmd)); } /* Read AIK from OpenSSL file */ if ((f_in = fopen (av[1], "rb")) == NULL) { fprintf (stderr, "Unable to open file %s\n", av[1]); exit (1); } if ((aikRsa = PEM_read_RSA_PUBKEY(f_in, NULL, NULL, NULL)) == NULL) { fprintf (stderr, "Unable to read RSA file %s\n", av[1]); exit (1); } fclose (f_in); /* Read quote file */ if ((f_in = fopen (av[2], "rb")) == NULL) { fprintf (stderr, "Unable to open file %s\n", av[2]); exit (1); } fseek (f_in, 0, SEEK_END); quoteLen = ftell (f_in); fseek (f_in, 0, SEEK_SET); quote = malloc (quoteLen); 75 if (fread (quote, 1, quoteLen, f_in) != quoteLen) { fprintf (stderr, "Unable to read file %s\n", av[2]); exit (1); } fclose (f_in); /* Parse quote file */ if (quoteLen < 2) goto badquote; selectLen = ntohs (*(UINT16*)quote); if (2 + selectLen + 4 > quoteLen) goto badquote; select = quote + 2; pcrLen = ntohl (*(UINT32*)(quote+2+selectLen)); if (2 + selectLen + 4 + pcrLen + 20 > quoteLen) goto badquote; pcrs = select + selectLen + 4; sig = pcrs + pcrLen; sigLen = quote + quoteLen - sig; /* Create TPM_QUOTE_INFO struct */ qinfo[0] = 1; qinfo[1] = 1; qinfo[2] = 0; qinfo[3] = 0; qinfo[4] = 'Q'; qinfo[5] = 'U'; qinfo[6] = 'O'; qinfo[7] = 'T'; SHA1 (quote, 2+selectLen+4+pcrLen, qinfo+8); memcpy (qinfo+8+20, chalmd, 20); /* Verify RSA signature */ SHA1 (qinfo, sizeof(qinfo), md); if (1 != RSA_verify(NID_sha1, md, sizeof(md), sig, sigLen, aikRsa)) { fprintf (stderr, "Error, bad RSA signature in quote\n"); exit (2); } /* Print out PCR values */ for (pcr=0; pcr < 8*selectLen; pcr++) { if (select[pcr/8] & (1 << (pcr%8))) { printf ("%2d ", pcr); for (i=0; i<20; i++) { printf ("%02x", pcrs[20*pcri+i]); } printf ("\n"); pcri++; } } fflush (stdout); fprintf (stderr, "Success!\n"); return 0; badquote: fprintf (stderr, "Input AIK quote file incorrect format\n"); return 1; } 76 create_tpm_key.c /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ Copyright (C) International Business Machines Corp., 2005-2006 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2. This program is but WITHOUT ANY MERCHANTABILITY the GNU General distributed in the hope that it will be useful, WARRANTY; without even the implied warranty of or FITNESS FOR A PARTICULAR PURPOSE. See Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =================================================================== In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. =================================================================== /* * Modifications by Jonathan Buhacoff. * Original source available at http://sourceforge.net/projects/trousers/files/OpenSSL%20TPM%20Engine/ */ #include #include #include #include #include <stdio.h> <getopt.h> <string.h> <strings.h> <errno.h> #include #include #include #include <openssl/rsa.h> <openssl/pem.h> <openssl/evp.h> <openssl/err.h> #include <trousers/tss.h> #include <trousers/trousers.h> // modification by jbuhacoff ... config.h is to read the owner password #include "config.h" // modification by jbuhacoff ... hex.h is to read the pcr manifest for sealing #include "hex.h" #define print_error(a,b) \ fprintf(stderr, "%s:%d %s result: 0x%x (%s)\n", __FILE__, __LINE__, \ a, b, Trspi_Error_String(b)) 77 static struct option long_options[] = { {"enc-scheme", 1, 0, 'e'}, {"sig-scheme", 1, 0, 'q'}, {"key-size", 1, 0, 's'}, {"auth", 0, 0, 'a'}, {"popup", 0, 0, 'p'}, {"wrap", 1, 0, 'w'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; void usage(char *argv0) { fprintf(stderr, "\t%s: create a TPM key and write it to disk\n" "\tusage: %s [options] <filename>\n\n" "\tOptions:\n" "\t\t-e|--enc-scheme encryption scheme to use [PKCSV15] or OAEP\n" "\t\t-q|--sig-scheme signature scheme to use [DER] or SHA1\n" "\t\t-s|--key-size key size in bits [2048]\n" "\t\t-a|--auth require a password for the key [NO]\n" "\t\t-p|--popup use TSS GUI popup dialogs to get the password " "for the\n\t\t\t\t key [NO] (implies --auth)\n" "\t\t-w|--wrap [file] wrap an existing openssl PEM key\n" "\t\t-h|--help print this help message\n", argv0, argv0); exit(-1); } TSS_UUID SRK_UUID = TSS_UUID_SRK; void openssl_print_errors() { ERR_load_ERR_strings(); ERR_load_crypto_strings(); ERR_print_errors_fp(stderr); } RSA * openssl_read_key(char *filename) { BIO *b = NULL; RSA *rsa = NULL; b = BIO_new_file(filename, "r"); if (b == NULL) { fprintf(stderr, "Error opening file for read: %s\n", filename); return NULL; } if ((rsa = PEM_read_bio_RSAPrivateKey(b, NULL, 0, NULL)) == NULL) { fprintf(stderr, "Reading key %s from disk failed.\n", filename); openssl_print_errors(); } BIO_free(b); return rsa; } int openssl_get_modulus_and_prime(RSA *rsa, unsigned int *size_n, unsigned char *n, unsigned int *size_p, unsigned char *p) { /* get the modulus from the RSA object */ if ((*size_n = BN_bn2bin(rsa->n, n)) <= 0) { 78 openssl_print_errors(); return -1; } /* get one of the primes from the RSA object */ if ((*size_p = BN_bn2bin(rsa->p, p)) <= 0) { openssl_print_errors(); return -1; } return 0; } int main(int argc, char **argv) { TSS_HCONTEXT hContext; TSS_FLAG initFlags = TSS_KEY_TYPE_LEGACY | TSS_KEY_VOLATILE; // jbuhacoff changing from legacy to binding //TSS_FLAG initFlags = TSS_KEY_TYPE_BIND | TSS_KEY_STRUCT_KEY12 | TSS_KEY_VOLATILE; // jbuhacoff changing from legacy to binding TSS_HKEY hKey; TSS_HKEY hSRK; TSS_RESULT result; TSS_HPOLICY srkUsagePolicy, keyUsagePolicy, keyMigrationPolicy; TSS_HTPM hTPM; // added by jbuhacoff TSS_HPOLICY tpmUsagePolicy; // added by jbuhacoff BYTE *blob; UINT32 blob_size, srk_authusage; BIO *outb; ASN1_OCTET_STRING *blob_str; unsigned char *blob_asn1 = NULL; int asn1_len; char *filename, c, *openssl_key = NULL; int option_index, auth = 0, popup = 0, wrap = 0; UINT32 enc_scheme = TSS_ES_RSAESPKCSV15; UINT32 sig_scheme = TSS_SS_RSASSAPKCS1V15_DER; UINT32 key_size = 2048; RSA *rsa; while (1) { option_index = 0; c = getopt_long(argc, argv, "pe:q:s:ahw:", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': initFlags |= TSS_KEY_AUTHORIZATION; auth = 1; break; case 'h': usage(argv[0]); break; case 's': key_size = atoi(optarg); break; case 'e': if (!strncasecmp("oaep", optarg, 4)) { enc_scheme = TSS_ES_RSAESOAEP_SHA1_MGF1; } else if (strncasecmp("pkcs", optarg, 4)) { usage(argv[0]); } break; case 'q': 79 if (!strncasecmp("der", optarg, 3)) { sig_scheme = TSS_SS_RSASSAPKCS1V15_SHA1; } else if (strncasecmp("sha", optarg, 3)) { usage(argv[0]); } break; case 'p': initFlags |= TSS_KEY_AUTHORIZATION; auth = 1; popup = 1; break; case 'w': initFlags |= TSS_KEY_MIGRATABLE; wrap = 1; openssl_key = optarg; break; default: usage(argv[0]); break; } } /* set up the key option flags */ switch (key_size) { case 512: initFlags |= TSS_KEY_SIZE_512; break; case 1024: initFlags |= TSS_KEY_SIZE_1024; break; case 2048: initFlags |= TSS_KEY_SIZE_2048; break; case 4096: initFlags |= TSS_KEY_SIZE_4096; break; case 8192: initFlags |= TSS_KEY_SIZE_8192; break; case 16384: initFlags |= TSS_KEY_SIZE_16384; break; default: usage(argv[0]); break; } #if 0 while (argc--) { printf("argv[%d] = \"%s\"\n", argc, argv[argc]); } exit(1); #endif filename = argv[argc - 1]; if (argc < 2 || filename[0] == '-') usage(argv[0]); //Create Context if ((result = Tspi_Context_Create(&hContext))) { print_error("Tspi_Context_Create", result); exit(result); } //Connect Context if ((result = Tspi_Context_Connect(hContext, NULL))) { print_error("Tspi_Context_Connect", result); Tspi_Context_Close(hContext); exit(result); 80 } //Create Object if ((result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY, initFlags, &hKey))) { print_error("Tspi_Context_CreateObject", result); Tspi_Context_Close(hContext); exit(result); } if ((result = Tspi_SetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIGSCHEME, sig_scheme))) { print_error("Tspi_SetAttribUint32", result); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(result); } if ((result = Tspi_SetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_ENCSCHEME, enc_scheme))) { print_error("Tspi_SetAttribUint32", result); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(result); } //Load Key By UUID printf("loading SRK...\n"); // debug statement added by jbuhacoff if ((result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, SRK_UUID, &hSRK))) { print_error("Tspi_Context_LoadKeyByUUID", result); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(result); } if ((result = Tspi_GetAttribUint32(hSRK, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_AUTHUSAGE, &srk_authusage))) { print_error("Tspi_GetAttribUint32", result); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(result); } // jbuhacoff modification to set the srk password even though the attribute we tried to read above isn't set: BYTE srkSecret[] = TSS_WELL_KNOWN_SECRET; printf("srk_authusage is %d\n", srk_authusage); if((result = Tspi_GetPolicyObject (hSRK, TSS_POLICY_USAGE, &srkUsagePolicy)) != TSS_SUCCESS) { print_error("Cannot load SRK", result); exit(result); } //result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_SHA1, result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_PLAIN, // changed from MODE_SHA1 to MODE_PLAIN in order to get it to work -- important difference from the other commands... jbuhacoff sizeof(srkSecret), srkSecret); if( result != TSS_SUCCESS ) { printf("cannot set srk secret\n"); exit(1); } printf("set srk password (length %lu)\n", sizeof(srkSecret)); // jbuhacoff modification to set the owner password: result = Tspi_Context_GetTpmObject (hContext, &hTPM); 81 result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &tpmUsagePolicy); result = Tspi_Policy_AssignToObject(tpmUsagePolicy, hTPM); char *ownerSecret = read_owner_secret("."); // TODO add command line option to configure this printf("set owner password (length %lu)\n", strlen(ownerSecret)); result = Tspi_Policy_SetSecret (tpmUsagePolicy, TSS_SECRET_MODE_PLAIN, strlen(ownerSecret), (BYTE *)ownerSecret); if (srk_authusage) { char *authdata = calloc(1, 128); if (!authdata) { fprintf(stderr, "malloc failed.\n"); Tspi_Context_Close(hContext); exit(result); } if ((result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy))) { print_error("Tspi_GetPolicyObject", result); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); free(authdata); exit(result); } if (EVP_read_pw_string(authdata, 128, "SRK Password: ", 0)) { Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); free(authdata); exit(result); } //Set Secret if ((result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_PLAIN, strlen(authdata), (BYTE *)authdata))) { print_error("Tspi_Policy_SetSecret", result); free(authdata); Tspi_Context_Close(hContext); exit(result); } free(authdata); } if (auth) { if ((result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &keyUsagePolicy))) { print_error("Tspi_Context_CreateObject", result); Tspi_Context_Close(hContext); exit(result); } if (popup) { //Set Secret if ((result = Tspi_Policy_SetSecret(keyUsagePolicy, TSS_SECRET_MODE_POPUP, 0, NULL))) { print_error("Tspi_Policy_SetSecret", result); Tspi_Context_Close(hContext); 82 exit(result); } } else { char *authdata = calloc(1, 128); if (!authdata) { fprintf(stderr, "malloc failed.\n"); Tspi_Context_Close(hContext); exit(result); } if (EVP_read_pw_string(authdata, 128, "Enter Key Usage Password: ", 1)) { printf("Passwords do not match.\n"); free(authdata); Tspi_Context_Close(hContext); exit(result); } //Set Secret if ((result = Tspi_Policy_SetSecret(keyUsagePolicy, TSS_SECRET_MODE_PLAIN, strlen(authdata), (BYTE *)authdata))) { print_error("Tspi_Policy_SetSecret", result); free(authdata); Tspi_Context_Close(hContext); exit(result); } free(authdata); } if ((result = Tspi_Policy_AssignToObject(keyUsagePolicy, hKey))) { print_error("Tspi_Policy_AssignToObject", result); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(result); } } // Create or Wrap Key if (wrap) { char n[256], p[128]; unsigned int size_n, size_p; BYTE *pubSRK; /*Set migration policy needed to wrap the key*/ if ((result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_MIGRATION, &keyMigrationPolicy))) { print_error("Tspi_Context_CreateObject", result); Tspi_Context_Close(hContext); exit(result); } if (auth) { char *authdata = calloc(1, 128); if (!authdata) { fprintf(stderr, "malloc failed.\n"); Tspi_Context_Close(hContext); exit(result); } if (EVP_read_pw_string(authdata, 128, 83 "Enter Key Migration Password: ", 1)) { printf("Passwords do not match.\n"); free(authdata); Tspi_Context_Close(hContext); exit(result); } if ((result = Tspi_Policy_SetSecret(keyMigrationPolicy, TSS_SECRET_MODE_PLAIN, strlen(authdata), (BYTE *)authdata))) { print_error("Tspi_Policy_SetSecret", result); Tspi_Context_Close(hContext); exit(result); } free(authdata); } if ((result = Tspi_Policy_AssignToObject(keyMigrationPolicy, hKey))) { print_error("Tspi_Policy_AssignToObject", result); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(result); } /* Pull the PubKRK out of the TPM */ if ((result = Tspi_Key_GetPubKey(hSRK, &size_n, &pubSRK))) { print_error("Tspi_Key_WrapKey", result); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(result); } Tspi_Context_FreeMemory(hContext, pubSRK); if ((rsa = openssl_read_key(openssl_key)) == NULL) { Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(-1); } if (RSA_size(rsa) != key_size / 8) { fprintf(stderr, "Error, key size is incorrect, please use the '-s' option\n"); RSA_free(rsa); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(-1); } if (openssl_get_modulus_and_prime(rsa, &size_n, (unsigned char *)n, &size_p, (unsigned char *)p)) { fprintf(stderr, "Error getting modulus and prime!\n"); RSA_free(rsa); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(-1); } if ((result = Tspi_SetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO, TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, size_n, (BYTE *)n))) { print_error("Tspi_SetAttribData (RSA modulus)", result); RSA_free(rsa); Tspi_Context_CloseObject(hContext, hKey); 84 Tspi_Context_Close(hContext); exit(-1); } if ((result = Tspi_SetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY, size_p, (BYTE *)p))) { print_error("Tspi_SetAttribData (private key)", result); RSA_free(rsa); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(-1); } if ((result = Tspi_Key_WrapKey(hKey, hSRK, 0))) { print_error("Tspi_Key_WrapKey", result); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(result); } } else { // jbuhacoff modification, here the third argument 0 was replaced with TSS_HPCRS hPcrComposite which indicates the PCR values to which the new key should be bound printf("creating seal-to-pcrs object...\n"); TSS_HPCRS hPcrs; // jbuhacoff result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS, TSS_PCRS_STRUCT_INFO,&hPcrs); //TSS_PCRS_STRUCT_INFO_SHORT,&hPcrs); unsigned char *pcrval = NULL; uint32_t pcrlen; FILE *pcrfile = fopen("pcr.manifest", "rb"); struct pcr_list pcrs = read_pcr_list(pcrfile); fclose(pcrfile); //read_pcr_manifest("/root/tlsea", "pcr.manifest", &hPcrs); // jbuhacoff char hexbuf[255]; int i; for(i=0; i<pcrs.length; i++) { bytearray2hex(pcrs.value[i].hash, hexbuf); printf("pcr manifest: %d %s\n", pcrs.value[i].index, hexbuf); result = Tspi_TPM_PcrRead(hTPM, pcrs.value[i].index, &pcrlen, &pcrval); unsignedchararray2hex(pcrval, pcrlen, hexbuf); printf(" actual value length %d: %s\n", pcrlen, hexbuf); // pcrs.value[i].hash.length == SHA1_LENGTH result = Tspi_PcrComposite_SetPcrValue(hPcrs, pcrs.value[i].index, pcrs.value[i].hash.length, pcrs.value[i].hash.data); if( result != TSS_SUCCESS ) { print_error("Tspi_PcrComposite_SetPcrValue", result); } //result = Tspi_PcrComposite_SelectPcrIndex(hPcrs, pcrs.value[i].index); //if( result != TSS_SUCCESS ) { //print_error("Tspi_PcrComposite_SelectPcrIndex", result); //} } printf("creating key...\n"); if ((result = Tspi_Key_CreateKey(hKey, hSRK, hPcrs)) != TSS_SUCCESS) { // jbuhacoff changed third argument from NULL to hPcrs to seal the key print_error("Tspi_Key_CreateKey", result); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(result); } } free(ownerSecret); // added by jbuhacoff 85 // XXX TODO jbuhacoff should we call Tspi_Key_CertifyKey to ask the tpm to certify the key we just made? that way when we send it // to the client, they can verify it was created by the TPM ... then they can replace the certificate with whatever THEY trust to // certify the public key (such as an attestation certificate authority). what key should be the certifying key? can it be the AIK ? // YEP... see also: // http://books.google.com/books?id=6fAQBkyK4UC&pg=PT175&lpg=PT175&dq=how+to+use+Tspi_Key_CertifyKey+with+aik&source=bl&ots=YKks mck4rG&sig=A6pgTQs7zoxrHMvygY7bpVslwA&hl=en&sa=X&ei=0pRhUfrJJITvigKXpYHgDA&ved=0CDoQ6AEwAQ // if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB, &blob_size, &blob))) { print_error("Tspi_GetAttribData", result); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(result); } if ((outb = BIO_new_file(filename, "w")) == NULL) { fprintf(stderr, "Error opening file for write: %s\n", filename); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(-1); } blob_str = ASN1_OCTET_STRING_new(); if (!blob_str) { fprintf(stderr, "Error allocating ASN1_OCTET_STRING\n"); Tspi_Context_CloseObject(hContext, hKey); Tspi_Context_Close(hContext); exit(-1); } ASN1_STRING_set(blob_str, blob, blob_size); asn1_len = i2d_ASN1_OCTET_STRING(blob_str, &blob_asn1); PEM_write_bio(outb, "TSS KEY BLOB", "", blob_asn1, asn1_len); BIO_free(outb); Tspi_Context_Close(hContext); printf("Success.\n"); return 0; } 86 APPENDIX B APPENDIX B. DEMONSTRATION Client The following example is real output from the client after typing in the command shown below and sending the text “hello world” shown in bold: openssl s_client -connect 192.168.1.42:7777 -tls1 -CAfile ca.crt CONNECTED(00000003) depth=1 C = US, ST = California, L = Sacramento, O = CSUS, OU = ECS, CN = TrustAuthority verify return:1 depth=0 C = US, ST = California, L = Sacramento, O = CSUS, CN = 192.168.1.42 verify return:1 --Certificate chain 0 s:/C=US/ST=California/L=Sacramento/O=CSUS/CN=192.168.1.42 i:/C=US/ST=California/L=Sacramento/O=CSUS/OU=ECS/CN=TrustAuthority 1 s:/C=US/ST=California/L=Sacramento/O=CSUS/OU=ECS/CN=TrustAuthority i:/C=US/ST=California/L=Sacramento/O=CSUS/OU=ECS/CN=TrustAuthority --Server certificate -----BEGIN CERTIFICATE----MIICvDCCAiUCAQIwDQYJKoZIhvcNAQEFBQAwbTELMAkGA1UEBhMCVVMxEzARBgNV BAgMCkNhbGlmb3JuaWExEzARBgNVBAcMClNhY3JhbWVudG8xDTALBgNVBAoMBENT VVMxDDAKBgNVBAsMA0VDUzEXMBUGA1UEAwwOVHJ1c3RBdXRob3JpdHkwHhcNMTMw NDE4MTk0ODM1WhcNMTQwNDE4MTk0ODM1WjBcMQswCQYDVQQGEwJVUzETMBEGA1UE CAwKQ2FsaWZvcm5pYTETMBEGA1UEBwwKU2FjcmFtZW50bzENMAsGA1UECgwEQ1NV UzEUMBIGA1UEAwwLMTAuMS43MS4xNjcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQC822Vk8HSEjER5PRv4AmNJrcuanKmcgW8dfsxLdvN162BYTlv+BIAd IkGDYmcDJY9N68ePbl+clrLgFbRTooYkgX+NgEk+yZ6CDxXSP0/+Cz7yAcKEa0cU bSFMgy8qW8SV05Gt+skNNR9hWJBFv85XePQBpFjGEDwCS184hgsYeGq9wyg6j1j3 0+0iWPIbOEyuRLBO8ekHL+KuEbWTDZrJRKqoCNmfB7sngljN0P18zKjEpI9m6UUu GmaOms8RqFecXYSeJfgxPLza7B9lQpDAE9VtkdylrXXYirwMNZmluRKTrhzSW9p0 5WnByMvVfqY9UWDLtpQHXJGG/DmAbrMbAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEA ui/jxyEV8mOmOS8oTJs+e6llWv33liFlAMjE3OrNng93g6kaxFed/4KVa2VvB7aq JLyL0nEw3bjSdnw/XigCo+k8Y7TqKDfS4AGAsdrUYcV+Qv7486pfERrN+3cY09k3 9IVF1XfSjef1qTLj8Yus4Qm5PL/S0iZfj0WiUU70qME= -----END CERTIFICATE----subject=/C=US/ST=California/L=Sacramento/O=CSUS/CN=192.168.1.42 issuer=/C=US/ST=California/L=Sacramento/O=CSUS/OU=ECS/CN=TrustAuthority --No client certificate CA names sent --SSL handshake has read 2022 bytes and written 361 bytes --New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : DHE-RSA-AES256-SHA Session-ID: A77B06C3AA8523E9D21B5FE1013128D13F968928708E42AFD5D47EFA3852B069 Session-ID-ctx: 87 Master-Key: C6F979C7D1C0413F4183C8CF7F2811E5BDAA6485B75C6587F1DC56DCE5C7B7B3378453124AE71A260A28F8CE4 0810D57 Key-Arg : None PSK identity: None PSK identity hint: None SRP username: None TLS session ticket: 0000 - 7c d5 3d 34 25 a0 5d fd-f3 45 11 ca 25 db 33 7b |.=4%.]..E..%.3{ 0010 - 45 36 c2 ce 94 67 77 50-5a ac a8 7a 3f 17 c9 ee E6...gwPZ..z?... 0020 - 73 35 58 5b ac 46 17 10-1a 8d 05 a6 42 b1 dc 02 s5X[.F......B... 0030 - 56 19 f5 43 91 21 49 75-15 11 96 d1 1c b2 45 3a V..C.!Iu......E: 0040 - 86 bb e7 73 37 54 15 8c-74 66 72 24 6a 7b bb ce ...s7T..tfr$j{.. 0050 - 5b 11 5e dd f8 9f 17 f2-43 42 bb 02 ed d0 96 30 [.^.....CB.....0 0060 - 84 21 ab f4 a8 13 85 76-d1 8c 0c c7 4c da 18 c3 .!.....v....L... 0070 - 0a 40 f4 67 42 2e 91 0e-9e aa c9 bf 53 07 ec 2f .@.gB.......S../ 0080 - cd 71 3a 1b 13 02 8d e3-c1 ff 24 01 a4 0e c7 4a .q:.......$....J 0090 - 0f b8 ed 55 0c 03 0b 55-af 8f 10 cc 73 f5 32 0d ...U...U....s.2. Start Time: 1366314721 Timeout : 7200 (sec) Verify return code: 0 (ok) --hello world DONE Server The following example is real output from the server after typing in the command and receiving a connection from the client as shown above. In the following command, a backslash at the end of a line indicates the next line is a continuation: openssl s_server -accept 7777 -tls1 -cert ssl.tpm.crt -key ssl.tpm.key -CAfile ca.crt \ -keyform engine -engine tpm engine "tpm" set. Using default temp DH parameters ACCEPT -----BEGIN SSL SESSION PARAMETERS----MFUCAQECAgMBBAIAOQQABDDG+XnH0cBBP0GDyM9/KBHlvapkhbdcZYfx3Fbc5ce3 szeEUxJK5xomCij4zkCBDVehBgIEUXBOpaIEAgIcIKQGBAQBAAAA -----END SSL SESSION PARAMETERS----Shared ciphers:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSSCAMELLIA256-SHA:AES256-SHA:CAMELLIA256-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DESCBC3-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:DHE-RSACAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:AES128-SHA:SEED-SHA:CAMELLIA128-SHA:RC4-SHA:RC4MD5:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DES-CBC-SHA:EXP-EDH-RSA-DES-CBC-SHA:EXP-EDHDSS-DES-CBC-SHA:EXP-DES-CBC-SHA:EXP-RC2-CBC-MD5:EXP-RC4-MD5 CIPHER is DHE-RSA-AES256-SHA Secure Renegotiation IS supported hello world DONE shutting down SSL CONNECTION CLOSED ACCEPT 88 APPENDIX C APPENDIX C. SECURITY TESTS When the server is configured to use a private key that doesn’t match the certificate, the OpenSSL s_server program displays this error: 140719700924232:error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch:x509_cmp.c:325: The return value comes from the OpenSSL function EVP_PKEY_cmp(xk, k); where xk is the public key embedded in the x509 certificate x, and k is the private key that was passed into X509_check_private_key(X509 *x, EVP_PKEY *k). Chapter 3 and Appendix B demonstrate how things are supposed to work. If the server that is configured in that demonstration were to extend one of its certified PCRs and restart the s_server, it should not be able to use the key that was sealed with the previous PCR values. Create pcr.manifest and an SSL key (the create_tpm_key command automatically uses the pcr.manifest file in the current directory): showpcr 0 17 18 19 20 > pcr.manifest cat pcr.manifest 0 891eb0b556b83fcef1c10f3fa6464345e34f8f91 17 bfc3ffd7940e9281a3ebfdfa4e0412869a3f55d8 18 dc3831d76dbb34f8906c1f9e14fc99ed227bb817 19 064d4c4f0eecb20a1d2b512ae80d7df6af612d01 20 0000000000000000000000000000000000000000 create_tpm_key ssl.tpm.key showpcr 0 0 891eb0b556b83fcef1c10f3fa6464345e34f8f91 Now extend PCR 0 with random bytes to change its value: openssl rand 20 > pcr.0.extend 89 extendpcr 0 pcr.0.extend showpcr 0 0 8c750d6142e5952e885da4049cb1bf4ee11a87f8 Now start the server and wait for a connection. Note that the output after “ACCEPT” is emitted after the client tries to connect. In the following command, a backslash at the end of a line indicates the next line is a continuation: openssl s_server -accept 7777 -cert ssl.tpm.crt -key ssl.tpm.key -CAfile ca.crt \ -keyform engine -engine tpm -tls1 engine "tpm" set. Using default temp DH parameters ACCEPT ERROR 139892261648200:error:8006906D:tpm engine:TPM_RSA_PRIV_ENC:request failed:e_tpm.c:1104: 139892261648200:error:1409B004:SSL routines:SSL3_SEND_SERVER_KEY_EXCHANGE:RSA lib:s3_srvr.c:1784: shutting down SSL CONNECTION CLOSED ACCEPT Try a connection to the untrusted server: openssl s_client -connect 192.168.1.42:7777 -tls1 CONNECTED(00000003) 139720757364552:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184: --no peer certificate available --No client certificate CA names sent --SSL handshake has read 0 bytes and written 113 bytes --New, (NONE), Cipher is (NONE) Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE --- 90 Notice that it says no peer certificate available, and the connection failed (no user input was possible, client exited). 91 APPENDIX D APPENDIX D. OPENSSL Downloading OpenSSL The OpenSSL source code is available at http://www.openssl.org/source/. Installing OpenSSL The procedure to install OpenSSL is comprised of three steps. First, unzip the OpenSSL package into a directory. Second, build OpenSSL as a shared library. It will be installed into /usr/local/ssl. Third, advertise the OpenSSL library to the linker. This step is only required on the server, where OpenSSL is linked to various Trousers components. gunzip -c openssl-1.0.1e.tar.gz | tar xf cd openssl-1.0.1e && ./config --shared && make && make test && make install echo /usr/local/ssl/lib > /etc/ld.so.conf.d/openssl.conf && ldconfig 92 APPENDIX E APPENDIX E. TROUSERS Downloading Trousers Trousers source code is available at http://sourceforge.net/projects/trousers/files/. You will need to download three packages: trousers, tpm-tools, and openssl_tpm_engine. Installing Trousers, TPM Tools, and TPM Engine for OpenSSL The installation procedure for each of the Trousers packages is comprised of three steps. First, unpack the downloaded file into a directory. Second, run the configuration and build scripts. Third, advertise the library to the linker. The third step is not necessary for TPM Tools because they are stand-alone commands. Trousers gunzip -c trousers-0.3.10.tar.gz | tar xf cd trousers-0.3.10 && sh bootstrap.sh && ./configure --prefix=/usr/local && \ make && make install echo /usr/local/lib > /etc/ld.so.conf.d/trousers.conf && ldconfig TPM Tools gunzip -c tpm-tools-1.3.8.tar.gz | tar xf cd tpm-tools-1.3.8 && LDFLAGS="-L/usr/local/lib" ./configure -prefix=/usr/local \ && make && make install TPM Engine for OpenSSL The library will be installed in /usr/local/lib/openssl/engines. gunzip -c openssl_tpm_engine-0.4.2.tar.gz | tar xf - 93 cd openssl_tpm_engine-0.4.2 && LDFLAGS="-L/usr/local/lib" ./configure \ --with-openssl=/usr/local/ssl && make && make install echo /usr/local/lib/openssl/engines > /etc/ld.so.conf.d/openssl_tpm_engine.conf && ldconfig export LD_LIBRARY_PATH=/usr/local/lib/openssl/engines \ 94 BIBLIOGRAPHY [1] Morgan Stanley, "Cloud Computing Takes Off," 2011. [Online]. Available: http://www.morganstanley.com/views/perspectives/cloud_computing.pdf. [2] C. Nachenberg, "Computer Virus Coevolution," Communications of the ACM, pp. 46-51, January 1997. [3] G. H. Kim and E. H. Spafford, "The Design and Implementation of Tripwire: A File System Integrity Checker," Purdue University Libraries, West Lafayette, 1993. [4] S. N. Chari and P.-C. Cheng, "BlueBoX: A policy-driven, host-based intrusion detection system," ACM Transactions on Information and System Security, vol. 6, no. 2, pp. 173-200, 2003. [5] A. Cui, M. Costello and S. J. Stolfo, "When Firmware Modifications Attack: A Case Study of Embedded Exploitation," Columbia University, New York, 2013. [6] K. Hall, T. Lendacky, E. Ratliff and K. Yoder, "Trusted Computing and Linux," IBM, 2005. [7] G. Coker, J. Guttman, P. Loscocco, A. Herzog, J. Millen, B. O'Hanlon, J. Ramsdell, A. Segall, J. Sheehy and B. Sniffen, "Principles of Remote Attestation," 2009. [Online]. Available: http://web.cs.wpi.edu/~guttman/pubs/good_attest.pdf. [8] R. Ng, "Trusted Platform Module Fundamental," in APTISS, 2008. [9] Trusted Computing Group, "TCG Specification Architecture Overview," August 2007. [Online]. Available: 95 http://www.trustedcomputinggroup.org/files/resource_files/AC652DE1-1D09-3519ADA026A0C05CFAC2/TCG_1_4_Architecture_Overview.pdf. [10] Trusted Computing Group, "TCG Software Stack (TSS) Specification Version 1.2," January 2006. [Online]. Available: http://www.trustedcomputinggroup.org/files/resource_files/647A8E37-1D09-3519AD860BD090352A8B/TSS_Version_1.2_Level_1_FINAL.pdf. [11] M. Strasser and H. Stamer, "A Software-Based Trusted Platform Module Emulator," in First International Conference on Trusted Computing and Trust in Information Technologies, Villach, Austria, 2008. [12] D. Grawrock, Dynamics of a Trusted Platform: A Building Block Approach, Hillsboro: Intel Press, 2009. [13] T. Dierks and E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.2," Internet Engineering Task Force, 2008. [14] D. Wagner and B. Schneier, "Analysis of the SSL 3.0 Protocol," April 1997. [Online]. Available: http://www.schneier.com/paper-ssl-revised.pdf. [15] S. Turner and T. Polk, "Prohibiting Secure Sockets Layer (SSL) Version 2.0," Internet Engineering Task Force, 2011. [16] E. Brickell, J. Camenisch and L. Chen, "Direct Anonymous Attestation," February 2004. [Online]. Available: http://eprint.iacr.org/2004/205.pdf. [17] E. Brickell and J. Li, "Enhanced Privacy ID: A Direct Anonymous Attestation 96 Scheme with Enhanced Revocation Capabilities," in ACM Workshop on Privacy in Electronic Society, New York, 2007. [18] M. Marlinspike, "New Tricks for Defeating SSL In Practice," in BlackHat, Washington DC, 2009. [19] T. Habets, "TPM-Backed SSL," 2012. [Online]. Available: http://blog.habets.pp.se/2012/02/TPM-backed-SSL. [20] K. Yoder, "Trousers FAQ," [Online]. Available: http://trousers.sourceforge.net/faq.html#5.1. [Accessed 2013].