aikquote.c - Sacramento

advertisement
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].
Download