CDRL A001 Final Report December 28, 2004
Final ReportPrincipled Assuredly Trustworthy
Composable Architectures
Submitted by:
Peter G. Neumann, Principal Investigator
Principal Scientist, Computer Science Laboratory
SRI International EL-243, 333 Ravenswood Ave
Menlo Park, California 94025-3493, USA
Neumann@csl.sri.com; http://www.csl.sri.com/neumann
Phone: 1-650-859-2375; Fax: 1-650-859-2844
Prepared for:
Contracting Officer, Code D4121
SPAWAR Systems Center
San Diego, California
Approved:
Patrick Lincoln, Director
Computer Science Laboratory
William Mark, Vice President
Information and Computing Sciences Division
This report is available on-line for browsing
http://www.csl.sri.com/neumann/chats4.html
and also for printing or displaying
http://www.csl.sri.com/neumann/chats4.pdf
http://www.csl.sri.com/neumann/chats4.ps
This document is the final report
for Task 1 of SRI Project 11459,
Architectural Frameworks for Composable Survivability and Security, under
DARPA Contract No. N66001-01-C-8040 as part of DARPA's Composable
High-Assurance Trustworthy Systems (CHATS) program.
Douglas Maughan was the DARPA Program Manager
through the first two years of the project. He has been succeeded
by Tim Gibson. Acknowledgments are given at the end of the body of this report.
However, the author would like to give special mention to the significant
contributions of Drew Dean and Virgil
Gligor. This report contains no proprietary or sensitive information.
Its contents may be freely disseminated.
All product and company names mentioned in this report are trademarks of their
respective holders.
This report presents the results of our DARPA CHATS project. We
characterize problems in and approaches to attaining computer system and
network architectures. The overall goal is to be better able to develop and
more rapidly configure highly trustworthy systems and networks able to
satisfy critical requirements (including security, reliability,
survivability, performance, and other vital
characteristics). We consider ways to enable effective systems to be
predictably composed
out of interoperable subsystems, to
provide the required trustworthiness -- with reasonably high assurance that
the critical requirements will be met under the specified operational
conditions, and (we hope) that do something sensible outside of that range
of operational conditions. This work thus spans the entire set of goals of
the DARPA CHATS program -- trustworthiness, composability, and assurance
-- and much more.
By trustworthiness,
we mean simply worthy of being trusted to
fulfill whatever critical requirements may be needed for a particular
component, subsystem, system, network, application, mission, enterprise, or
other entity. Trustworthiness requirements might typically involve (for
example) attributes of security, reliability, performance, and survivability
under a wide range of potential adversities. Measures of trustworthiness
are meaningful only to the extent that (a) the requirements are sufficiently
complete and well defined, and (b) can be accurately evaluated.
This report should be particularly valuable to system developers who have
the need and/or the desire to build systems and networks that are
significantly better than today's conventional mass-market and custom
software. The conclusions of the report can also be useful to government
organizations that fund research and development efforts, and to procurers
of systems that must be trustworthy.
In this report, we confront an extremely difficult problem -- namely, how
to attain demonstrably trustworthy systems and networks that must operate
under stringent requirements for security, reliability, survivability, and
other critical attributes, and that must be able to evolve gracefully and
predictably over time -- despite
changes in requirements, hardware, communications technologies, and
radically new applications. In particular, we seek to establish a sound
basis for the creation of trustworthy systems and networks that can be
easily composed out of subsystems and components, with
predictably high assurance, and also do
something sensible when forced to operate predictably outside of the
expected normal range of operational conditions. Toward this end, we
examine a set of principles for achieving trustworthiness, consider
constraints that might enhance composability, pursue architectures and trustworthy subsystems that are inherently likely
to result in trustworthy systems and networks, define constraints on administrative practices that reduce operational risks, and seek approaches
that can significantly increase assurance. The approach is intended
to be theoretically sound as well as practical and realistic. We also
outline directions for new research and development that could significantly
improve the future for high-assurance trustworthy systems.
With respect to the future of trustworthy systems and networks, perhaps the
most important recommendations involve the urgent establishment and use of
soundly based, highly disciplined, and principle-driven architectures,
as well as development practices that systematically encompass
trustworthiness and assurance as integral parts of what must become coherent
development processes and sound subsequent operational practices. Only
then can we have any realistic assurances that our computer-communication
infrastructures -- and indeed our critical national infrastructures --
will be able to behave as needed, in times of crisis as well as in normal
operation. The challenges do not have easy turn-the-crank solutions.
Addressing them requires considerable skills, understanding, experience,
education, and enlightened management. Success can be greatly increased in
many ways, including the availability of reliable hardware components,
robust and resilient network architectures and systems, consistent use of
good software engineering practices, careful attention to human-oriented
interface design, well-conceived and sensibly used programming languages,
compilers that are capable of enhancing the trustworthiness of source code,
techniques for increasing interoperability among heterogeneous distributed
systems and subsystems, methods and tools for analysis and assurance, design
and development of systems that are inherently easier to administer and
that provide better support for operational personnel, and many other
factors. The absence or relative inadequacy with respect to each of these
factors today represents a potential weak link in a process that is
currently riddled with too many weak links. On the other hand, much greater
emphasis on these factors can result in substantially greater
trustworthiness, with predictable results.
The approach taken here is strongly motivated by historical perspectives
of promising research efforts and extensive development experience (both
positive and negative) relating to the development of trustworthy systems.
It is also motivated by the practical needs and limitations of commercial
developments as well as some initial successes in inserting significantly
greater discipline into the open-source world. It provides useful
guidelines for disciplined system developments and future research.
This report cannot be everything for everyone, although it should have some
appeal to a relatively broad range of readers. As a consequence of the
inherent complexity associated with the challenges of developing and
operating trustworthy systems and networks, we urge readers with experience
in software development to read this report thoroughly, to see what
resonates nicely with their experience. However, to the inexperienced
developer or to the experienced developer who believes in seat-of-the-pants
software creation, we offer a few words of caution. Many of the individual
concepts should be well known to many of you. However, if you are looking
for easy answers, you may be disappointed; indeed, each chapter should in
turn convince you that there are no easy answers. On the other hand, if you
are looking for some practical advice on how to develop systems that are
substantially more trustworthy than what is commercially available today,
you may find many encouraging directions to pursue.
Although there are some novel concepts in this report, our main thrust
involves various approaches that can make better use of what we have learned
over the past many years in the research community and that can be used to
better advantage in production systems. Many of the lessons relating to
serious trustworthiness can be drawn from past research and prototype
development. However, those lessons have been largely ignored in commercial
development communities, and perhaps have also been insufficiently observed
by the developers of source-available software. There are many directions
herein -- both new and old -- for fruitful research and development that
can help to fill in the gaps.
We believe that observance of the approaches described here would greatly
improve the present situation. The opportunities for this within the
open-source community are considerable, although they are also applicable to
closed-source proprietary systems (despite various caveats).
The outline of this report is as follows.
In the context of this report, the term
"trustworthy" is used in a broad sense that is
meaningful with respect to any given set of requirements, policies,
properties, or other definitional entities. It represents the extent to
which those requirements are likely to be satisfied, under specified
conditions. That is, trustworthiness means worthy of being trusted to
satisfy the given expectations. For example, typical requirements might
relate to attributes of security, reliability, performance, and
survivability under a wide range of potential adversities. Each of these
attributes has expectations that are specific to each layer of abstraction
(and differing from one layer to another) -- for example, with respect to
hardware, operating systems, applications, systems, networks, and enterprise
layers.
Note that these concepts are sometimes interrelated. Achieving
survivability in turn requires security, reliability, and some measures of
guaranteed performance (among other requirements). Human safety typically
does as well. Many of these properties are meaningful in different ways at
various layers of abstraction. At the highest layers, they tend to be
emergent properties of systems in the large, or
indeed entire enterprises -- that is, they are meaningful only in terms of
the entire system complex rather than as lower-layer properties.
The concept of trustworthiness is essentially indistinguishable from
what is termed dependability [24, 25, 26, 202, 309],
particularly within the IEEE and European communities.
In its very early days, dependability was focused primarily on hardware
faults, subsequently extended to software faults, and then generalized to a
notion of faults that includes security threats. In that framework,
dependability's generalized notions of fault
prevention, fault tolerance,
fault removal, and fault
forecasting (the last of which has some of the
elements of assurance) seem to encompass everything that trustworthiness
does, albeit with occasionally different terminology. However, a recent
paper, Basic Concepts and Taxonomy of Dependable and Secure Computing, by
Avizienis, Laprie, Randell, Landwehr [26] (which is a
gold mine for serious researchers) attempts to distinguish security as a
specifically identifiable subset of dependability, rather than more
generally treating it as one of various sets of
application-relevant requirements subsumed
under trustworthiness, as we do in this report. (Their new reformulation of
security encompasses primarily confidentiality, integrity, and availability
-- which in this report are only part of the necessary trustworthiness aspects
that are required for security -- although it also alludes to other
attributes of security. However, any differences between their paper and
this report are largely academic -- we are each approaching the same
basic problems.)
We make a careful distinction throughout this report
between trust and trustworthiness. Trustworthiness
implies that something is worthy of being trusted. Trust
merely implies that you trust something
whether it is trustworthy or not, perhaps
because you have no alternative, or because you are naive, or perhaps
because you do not even realize that trustworthiness is necessary, or
because of some other reason.
We generally eschew the terms trust
and trusted unless we specifically mean trust rather than
trustworthiness. (The slogan on an old T-shirt worn around the
National Security Agency was "In trust we trust.")
A prophetic definition long ago due to Leslie Lamport
can be paraphrased in the context of this report
as follows: a distributed system is a system in which you have to
trust components whose mere existence may be unknown to you. This
is increasingly a problem on the World Wide Web, which is today's ultimate
distributed system.
There are many R&D directions that we believe are important for the short-
and long-term futures -- for the computer and network communities at large,
for DARPA developers, and for system and network developers generally. (We
outline some recommendations for future R&D in Chapter 9.) The
basis of our project is the exploration and exploitation of a few of the
potentially most timely and significant research and development directions.
Throughout the history of efforts to develop trustworthy systems and
networks, there is an unfortunate shortage of observable long-term progress
relating specifically to the multitude of requirements for security.
(See, for example, an interview with Richard Clarke [149] in
the IEEE Security and Privacy.) Blame can be widely distributed among
governments, industries, and users -- both personal and corporate.
Significant research and development results are typically soon forgotten or
else deprecated in practice. Systems have come and gone, programming
languages have come and (sometimes) gone, and certain specific systemic
vulnerabilities have come and gone. However, many generic classes of
vulnerabilities seem to persist forever -- such as buffer overflows, race
conditions, off-by-one errors, mismatched types, divide-by-zero crashes, and
unchecked procedure-call arguments, to name just a few. Overall, it is
primarily only the principles that have remained inviolable -- at least in
principle -- despite their having been widely ignored in practice. It is
time to change that unfortunate situation, and honor the principles.
There is an unfortunate shortage of fundamental books that provide useful
background for the material discussed in this report. Two recent books by
Matt Bishop,
Computer Security: Art and Science [47] and
Introduction to Computer Security [48], are worthy of
particular note -- the former for its rather comprehensive and somewhat
rigorous computer-science-based treatment of security, and the latter for
its less formal approach that should be more accessible to others who are
not computer scientists. Chuck Pfleeger's
Security in Computing [303],
Ross Anderson's Security
Engineering [14], and Morrie Gasser's
Building a Secure
Computer System [127] are also worthy sources. A recent book
by Ian Sommerville [359] provides extensive background on
software engineering.
A paper [266] summarizing our conclusions as of early 2003
is part of the DISCEX3 proceedings, from the April 2003 DARPA Information
Survivability Conference and Exposition.
Enormous benefits can result from basing requirements, architectures,
implementations, and operational practices on well-defined and
well-understood generally accepted principles.
In this chapter, we itemize, review, and interpret various design and
development principles that if properly observed can advance composability,
trustworthiness, assurance, and other attributes of systems and networks,
within the context of the CHATS effort. We consider the relative
applicability of those principles, as well as some of the problems they may
introduce.
A fundamental hypothesis motivating this report is that achieving
assurable trustworthiness requires much greater observance of certain
underlying principles. We assert that careful attention to such
principles can greatly facilitate the following efforts.
The benefits of disciplined
and principled
system development cannot be overestimated, especially in the early stages
of the development cycle. Principled design and software development can
stave off many problems later on in implementation, maintenance, and
operation. Huge potential cost savings can result from diligently observing
relevant principles throughout the development cycle and maintaining
discipline. But the primary concept involved is that of disciplined
development; there are many methodologies that provide some kind of
discipline, and all of those can be useful in some cases.
In concept, most of the principles discussed here are fairly well known and
understood by system cognoscenti. However, their relevance is often not
generally appreciated by people with little development or operational
experience. Not wishing to preach to the choir, we do not dwell on
elaborating the principles themselves, which have been extensively covered
elsewhere (see Section 2.3). Instead, we concentrate on the
importance and applicability of these principles in the development of
systems with critical requirements -- and especially secure systems and
networks. The clear implication is that disciplined understanding and
observance of the most effective of these principles can have enormous
benefits to developers and system administrators, and also can aid user
communities. However, we also explore various potential conflicts within
and among these principles, and emphasize that those conflicts must be
thoroughly understood and respected. System development is intrinsically
complicated in the face of critical requirements. For example, it is
important to find ways to manage that complexity, rather than to mistakenly
believe that intrinsic complexity is avoidable by pretending to practice
"simplicity".
As noted above, trustworthiness is a concept that encompasses
being worthy of trust with respect to whatever critical requirements
are in effect, often relating to security, reliability, guarantees
of real-time performance and resource availability, survivability
in spite of a wide range of adversities, and so on. Trustworthiness
depends on hardware, software, communications media, power supplies,
physical environments,
and ultimately people in many capacities -- requirements specifiers,
designers, implementers, users, operators, maintenance personnel,
administrators, and so on.
There are numerous examples of untrustworthy systems, networks,
computer-related applications, and people. We indicate the extensive
diversity of cases reported in the past with just a few tidbits relevant to
each of various categories. See Computer-Related
Risks [260] and the Illustrative Risks
index [267] for numerous further examples and references
involving many different types of system applications. (In the Illustrative
Risks document, descriptors indicate relevance to loss of life, system
survivability, various aspects of security, privacy, development problems,
human interface confusions, and so on.) Some of
these examples are revisited in Section 6.9, in considering how
principled architectures and assurance-based risk reduction might have
avoided the particular problems.
Many systems actually have critical requirements that span multiple areas
such as security, reliability, safety, and survivability. Although the
cases listed above generally result from a problem in primarily one of these
areas, there are many cases in which a maliciously induced security problem
could alternatively have resulted from an accidentally triggered reliability
problem, or -- similarly -- where a reliability/availability failure
could also have been triggered intentionally. (For example, see Chapter 4
of [260].)
One such application area with critical multidisciplinary requirements has
become of particular interest since the 2000 November election, resulting
from the emerging desire for completely electronic voting
systems that ideally should have stringent
requirements for system integrity, voter privacy, and accountability, and
-- perhaps most important -- the impossibility of uncontrolled human
intervention during elections. Some of today's major existing
all-electronic systems permit unmonitored human intervention (to recover
from election-day glitches and to "fix" problems -- including during the
voting and vote-counting procedures!), with no meaningful accountability.
Some systems even routinely undergo code changes after the software
has been certified! Thus, we are confronted with all-electronic paperless
voting systems that have no independent audit record of what has happened in
the system internals, with no real assurance that your vote was correctly
recorded and counted, with no alternative recount, no systemic way of
determining the presence of internal errors and fraud, and no evidence in
case of protests. The design specs and code are almost always proprietary,
and the system has typically been certified against very weak voluntary
standards that do not adequately detect fraud and internal accidents, with
evaluations that are commissioned and paid for by the vendors. In contrast,
gambling machines are regulated with extreme care (for example, by the
Nevada Gaming Commission), and held to extremely high standards.
For a partial enumeration of recorded cases of voting-system irregularities
over the past more than twenty years, see the online html version
of [267], clicking on Election Problems,
or see the corresponding section in the .pdf and .ps versions.
Section 5.2.2 reconsiders some of the above cases as well as
others in which problems arose specifically because of problems involving
the human interfaces.
Developing and operating complex systems and networks with critical
requirements demands a different kind of thinking from that used in routine
programming. We begin here by considering various sets of principles, their
applicability, and their limitations.
We first consider the historically significant Saltzer-Schroeder principles,
followed by several other approaches.
The ten basic security principles formulated by Saltzer and
Schroeder [334] in 1975 are all still relevant today, in
a wide range of circumstances. In essence, these principles are summarized
with a CHATS-relevant paraphrased explanation, as follows:
Remember that these are principles, not hard-and-fast rules. By no means
should they be interpreted as ironclad, especially in light of some of their
potential mutual contradictions that require development tradeoffs. (See
Section 2.6.)
The Saltzer-Schroeder principles grew directly out of the Multics
experience (e.g., [277]), discussed
further at the end of this section. Each of these principles has taken on
almost mythic proportions among the security elite, and to some extent
buzzword cult status among many fringe parties. Therefore, perhaps it is
not necessary to explain each principle in detail -- although there is
considerable depth of discussion underlying each principle. Careful reading
of the Saltzer-Schroeder paper [334] is recommended if
it is not already a part of your library.
Matt Bishop's
security
books [47, 48] are also useful in this regard, placing the
principles in a more general context. In addition, Chapter 6 of Matt
Curtin's book [89] on "developing trust" -- by which he might
really hope to be "developing trustworthiness" -- provides some useful
further discussion of these principles.
There are two fundamental caveats regarding these principles. First, each
principle by itself may be useful in some cases and not in others. The
second is that when taken in combinations, groups of principles are not
necessarily all reinforcing; indeed, they may seem to be mutually in
conflict. Consequently, any sensible development must consider appropriate
use of each principle in the context of the overall effort. Examples of a
principle being both good and bad -- as well as examples of interprinciple
interference -- are scattered through the following discussion. Various
caveats are considered in the penultimate section.
Table 1 examines the applicability of each of the
Saltzer-Schroeder principles to the CHATS goals of composability,
trustworthiness, and assurance (particularly with respect to security,
reliability, and other survivability-relevant requirements).
In particular, complete mediation, separation of privileges, and allocation
of least privilege are enormously helpful to composability and
trustworthiness. Open design can contribute significantly to composability,
when subjected to internal review and external criticism. However, there is
considerable debate about the importance of open design with respect to
trustworthiness, with some people still clinging tenaciously to the notion
that security by obscurity is sensible -- despite risks of many flaws being
so obvious as to be easily detected externally, even without reverse
engineering. Indeed, the recent emergence of very good
decompilers for C and Java, along with the likelihood of similar
reverse engineering tools for other languages, both suggest that such
attacks are becoming steadily more practical.
Overall, the assumption of design secrecy and the supposed
unavailability of source code is often not a deterrent, especially with
ever-increasing skills among black-box system analysts. However, there are
of course cases in which security by obscurity is unavoidable -- as in the
hiding of private and secret cryptographic keys, even where the
cryptographic algorithms and implementations are public.
Fundamental to trustworthiness is the extent to which systems and networks
can avoid being compromised
by malicious or accidental human behavior and by
events such as hardware malfunctions and so-called acts of God.
In [264], we consider compromise from outside, compromise
from within, and compromise from below,
with fairly intuitive meanings.
These notions appear throughout this report.
There are other cases in theory where weak links
can be avoided (e.g., zero-knowledge
protocols that can establish a shared key without any part of the protocol
requiring secrecy), although in practice they may be undermined by
compromises from below
(e.g., involving trusted and supposedly trustworthy
insiders subverting the underlying operating systems) or from outside
(e.g.,
involving penetrations of the operating systems and masquerading as
legitimate users). For a fascinating collection of papers on
vulnerabilities and ways to exploit
weak links, see Ross Anderson's website:
From its beginning, the Multics
development was strongly motivated by a set
of principles -- some of which were originally stated by Ted Glaser
and Peter Neumann in the first section of the very first edition of the Multics
Programmers' Manual in 1965.
(See http://multicians.org.)
It was also driven by extremely disciplined
development.
For example, with almost no
exceptions, no coding effort was begun until a written specification
had been approved by the Multics advisory board;
also with almost no exceptions, all of the code was written in a
subset of PL/I just sufficient for the initial needs of Multics,
for which the first compiler (early PL, or EPL) had been developed
by Doug McIlroy and Bob Morris.
In addition to the Saltzer-Schroeder
principles, further insights on principles and discipline relating to
Multics can be found in a paper by Fernando
Corbató, Saltzer, and Charlie Clingen [85] and in
Corbató's Turing lecture [84].
Another view of principled system development was given by Neumann in
1969 [255], relating to what is often dismissed as merely
"motherhood" -- but which in reality is both very profound and difficult
to observe in practice. The motherhood principles under consideration in
that paper (alternatively, you might consider them just as desirable system
attributes) included automatedness, availability, convenience,
debuggability, documentedness, efficiency,
evolvability, flexibility, forgivingness, generality, maintainability,
modularity, monitorability, portability, reliability,
simplicity, and uniformity. Some of those attributes indirectly affect
security and trustworthiness, whereas others affect the acceptability,
utility, and future life of the systems in question. Considerable
discussion in [255] was also devoted to (1) the risks of local
optimization and the need
for a more global awareness of less obvious downstream costs of development
(e.g., writing code for bad -- or nonexistent -- specifications, and
having to debug really bad code), operation, and maintenance (see
Section 7.1 of this report); and (2) the benefits of higher-level
implementation languages (which prior to Multics were rarely used for the
development of operating systems [84, 85]).
In later work and more recently in [264], Neumann considered
some extensions of the Saltzer-Schroeder principles. Although most of
those principles might seem more or less obvious, they are of course full of
interpretations and hidden issues. We summarize an extended set of
principles here, particularly as they might be interpreted in the CHATS
context.
Table 2 summarizes the utility of the extended-set
principles with respect to the three goals of the CHATS program acronym, as
in Table 1.
For example, authorization is of limited use without
authentication, whenever
identity is important. Similarly, authentication may be of questionable
use without authorization. In
some cases, authorization requires fine-grained access controls. Least
privilege requires some sort of separation of roles, duties, and domains.
Separation of duties is difficult to achieve if there is no separation of
roles. Separation of roles, duties, and domains each must rely on a
supporting architecture.
The comprehensive accountability principle is particularly
intricate, as it depends critically on many other principles being invoked.
For example, accountability is inherently incomplete without authentication
and authorization. In many cases,
monitoring may be in conflict with privacy
requirements and other social considerations [101],
unless extremely stringent controls are enforceable.
Separation of duties and least privilege are particularly important here.
All accountability procedures are subject to security attacks, and
are typically prone to covert channels as well. Furthermore, the procedures
themselves must be carefully monitored. Who monitors the monitors?
(Quis auditiet ipsos audites?)
Also of interest here is the 1993 set of principles (or perhaps
metaprinciples?) of secure design [56], which emerged from an NSA
ISSO INFOSEC Systems Engineering study on rules of system composition.
The study
was presented not as a finished effort, but rather as something that needed
to stand the test of practice. Although there is some overlap with the
previously noted principles, the NSA principles are enumerated here as they
were originally documented. Some of these principles are equivalent to
"the system should satisfy certain security requirements" -- but they are
nevertheless relevant. Others might sound like motherhood. Overall, they
represent some collective wisdom -- even if they are fairly abstract
and incompletely defined.
Considerable discussion of these metaprinciples is warranted. For example,
"Every component in a system must operate in a security environment that is
a subset of its specified environment" implies iteratively that maximum
trust is required throughout design and implementation of the other
components, which is a gross violation of our notion of minimization of what
must be trustworthy. It would be preferable to require that each component
check that the environment in which it executes is a subset of its specified
environment -- which is closely related to Schroeder's
notion of mutual suspicion [343],
noted further down the list.
"A system is only as strong as its weakest link" is generally a meaningful
statement. However, some weak links may be more devastating than others, so
this statement is overly simplistic. In combination with least privilege,
separation of domains, and some of the other principles noted previously,
the effects of a particular weak link might be contained or controlled. But
then, you might say, the weak link was not really a weak link. However, to
a first approximation, as we noted above, weak links should be avoided where
possible, and restricted in their effects otherwise, through sound
architecture and sound implementation practice.
The 1990 report of the National Research Council study group that produced
Computers at Risk [83] included a recommendation that a
serious effort be made to develop and promulgate a set of Generally Accepted
Systems Security Principles (GASSP). That led to the creation of the International
Information Security Foundation (I2SF). A draft of its GASSP
document [279] is available online. A successor effort is
under way, after a long pause.
The proposed GASSP consists of three layers of abstraction, nine Pervasive
Principles (relating to confidentiality, integrity, and availability), a set
of 14 Broad Functional Principles, and a set of Detailed Principles (yet to
be developed, because the largely volunteer project ran out of steam, in
what Jim Horning refers to as a last gassp!).
The GASSP effort thus far actually represents a very worthy beginning, and
one more approach for those interested in future efforts. The top two
layers of the GASSP principle hierarchy are summarized here as follows.
The GASSP document gives a table showing the relationships between the 14
Broad Functional Principles and the 9 Pervasive Principles. That table
is reproduced here as Table 3.
Any enumeration of relevant principles must note the historical evolution of
evaluation criteria over the past decades -- from the 1985 DoD Trusted
Computer System Evaluation Criteria
(TCSEC, a.k.a. The Orange
Book [249]) and the ensuing Rainbow Books, to the 1990 Canadian
Trusted Computer Product Evaluation Criteria (CTCPEC, [64]),
and
the 1991 Information Technology Security Evaluation Criteria
(ITSEC, [116]).
These efforts have resulted in an international
effort to produce the Common Criteria
framework (ISO 15408 [172]),
which represents the current state of the art in that particular
evolutionary process. (Applicability to multilevel security is also
addressed within the Common Criteria framework, although it is much more
deeply embedded in the higher-assurance levels of the TCSEC.)
A seemingly radical approach to software development is found in the Extreme
Programming (XP) movement [33].
(Its use of "XP" considerably predates Microsoft's.) Although XP appears to
run counter to most conventional programming practices, it is indeed highly
disciplined.
XP might be thought of as very small chief programmer teams
somewhat in the spirit of a Harlan Mills'
Clean-Room
approach, although it has no traces of formalism and is termed a
lightweight methodology. It involves considerable emphasis on
disciplined planning throughout (documented user stories, scheduling of
relatively frequent small releases, extensive iteration planning, and
quickly fixing XP whenever necessary), designing and redesigning throughout
(with simplicity as a driving force, the selection of a system metaphor, and
continual iteration), coding and recoding as needed (paired programmers
working closely together, continual close coordination with the customer,
adherence to agreed-upon standards, only one programmer pair may integrate
at one time, frequent integration, deferred optimization,
and no overtime pay),
and testing repeatedly throughout (code must pass unit tests before release,
tests must be created for each bug found, acceptance tests are run often,
and the results are published).
In essence, Extreme Programming seeks to have something running at the end
of each period (e.g., each week) by deferring less important concepts until
later. There is a stated desire to let business folks decide which features
to implement, based on the experience with the ongoing development.
Questions of how to address architecture in the large seem not to be
adequately addressed within Extreme Programming (although these questions
are absolutely fundamental to the approach that we are taking in this
report, but perhaps are considered extraneous to XP). The concept of
deferring architectural design until later in the process may work well in
small systems (where dynamic changes tend to be relatively local), but can
seriously complicate development of highly complex systems. Perhaps if
coupled with principled architectures recommended here, Extreme Programming
could be effective for larger development efforts. See the Web site noted
in [33] for considerable background on the XP movement, including a
remarkably lucid Frequently Asked Questions document contrasting XP with
several other approaches (UML, RUP,
CMM, Scrum, and FDD -- although this is a little like comparing apples and
oranges). Wikipedia also has a useful analysis of socalled agile or
lightweight methodologies, with relevant references
(http://en.wikipedia.org/wiki/Agile_software_development
).
There are too many other design and development methodologies to enumerate
here, ranging from very simple to quite elaborate. In some sense, it does
not matter which methodology is adopted, as long as it provides some
structure and discipline, and is relatively
compatible with the abilities of the particular design and development team.
For example, Dick Karpinski hands out a business
card containing his favorite, Tom Gilb's Project Management Rules: (1) Manage critical goals by defining
direct measures and specific targets; (2) Assure accuracy and quality with
systematic project document inspections; (3) Control major risks by limiting
the size of each testable delivery. These are nice goals, but depend on the
skills and experience of the developers -- with only subjective evaluation
criteria. Harlan Mills' "Clean-Room"
technology has some elements of formalism that are of interest with respect
to increasing assurance, although not specifically oriented toward security.
In general, good development practice is a necessary prerequisite for
trustworthy systems, as are means for evaluating that practice.
Some characteristic sources of security flaws in system design and
implementation are noted in [260], elaborating on earlier
formulations and refinements (e.g., [5, 271]). There
are various techniques for avoiding those flaws, including sound
architectures, defensively oriented programming languages, defensively
oriented compilers, better runtime environments, and generally better
software engineering practice.
Useful techniques for detecting some of these vulnerabilities include
defensive programming language design, compiler checks, and formal methods
analyzing consistency of programs with specifications. Of particular
interest is the use of static checking. Such an approach may be formally
based, as in the use of model checking by Hao Chen,
Dave Wagner, and Drew Dean
(in the MOPS system, developed in part under our CHATS project). (See
Appendix A.) Alternatively, there are numerous approaches that do
not use formal methods, ranging in sophistication from lint to LCLint (Evans) to Extended Static Checking (Nelson, Reino, et al.,
DEC/Compaq SRC). Note that ESC is completely formally based, including
use of a theorem prover; indeed, it is a formal method that has some utility
even in the absence of formal software specifications.
Jim Horning notes that even
partial specifications increase the power of the latter two, and provide a
relatively gentle way to incorporate additional formalism into development.
Strong type checking and model checking tend to expose various flaws, some
of which are likely to be consequential to security and reliability. For
example, purify and similar tools are useful in catching
memory leaks, array-bound violations, and related memory problems. These
and other analytic techniques can be very helpful in improving design
soundness and code quality -- as long as they are not relied on by
themselves as silver bullets.
All of the principles have some bearing on avoiding these classes
of vulnerabilities.
Several of these concepts in combination -- notably
modularity, abstraction,
encapsulation,
device independence where advantageous,
information hiding, complete mediation, separation of policy and mechanism,
separation of privilege, least privilege, and least common mechanism -- are
relevant to the notion of virtual interfaces and virtual machines. The
basic notion of virtualization is that it can mask many of the underlying
details, and makes it possible to change the implementation without changing
the interface. In this respect, several of these attributes are found in
the object-oriented paradigm.
Several examples of virtual mechanisms and virtualized interfaces are worth
noting. Virtual memory masks physical memory
locations and paging. A virtual machine masks the
representation of process state information and processor multiplexing.
Virtualized input-output masks device
multiplexing, device dependence, formatting, and timing. Virtual
multiprocessing masks the scheduling of tasks
within a collection of seemingly simultaneous processes. The Multics
operating system [277] provides early illustrations of virtual memory and virtual
secondary storage management (with demand paging hidden from the programs),
virtualized input-output (with symbolic stream names and device independence
where commonalities exist), and virtual multiprogramming (with scheduling
typically hidden from the programming interfaces). The GLU
environment [177] is an elegant illustration of virtual multiprocessing. GLU allows
programs to be distributed dynamically among different processing resources
without explicitly programmed processor allocation, based on precompiling of
embedded guidance in the programs.
In general, the task of providing some meaningful assurances that a system is
likely to do what is expected of it can be enhanced by any techniques that
simplify or narrow the analysis -- for example, by increasing the
discipline applied to system architecture,
software design, specifications, code style, and configuration
management. Most of the cited
principles tend to do exactly that -- if they are applied wisely.
Techniques for increasing assurance are considered in greater detail in
Chapter 6, including the potential roles of formal methods.
As we noted above, the principles referred to here may be in conflict with
one another if each is applied independently; in certain cases, the
principles are not composable. In general, each principle must be applied
in the context of the overall development. Ideally, greater effort might be
useful to reformulate the principles to make them more readily composable,
or at least to make their potential tradeoffs or incompatibilities more
explicit.
There are also various potentially harmful considerations that must be
considered -- for example, overuse, underuse, or misapplication of these
principles, and certain limitations inherent in the principles themselves.
Merely paying lipservice to a principle is clearly a bad idea; principles
must be sensibly applied to the extent that they are appropriate to the
given purpose. Similarly, all of the criteria-based methodologies have many
systemic limitations (e.g., [257, 372]); for example,
formulaic application of evaluation criteria is always subject to
incompleteness and misinterpretation of requirements, oversimplification in
analysis, and sloppy evaluations. However, when carefully applied, such
methodologies can be useful and add discipline to the development process.
Thus, we stress here the importance of fully understanding the given
requirements and of creating an overall architecture that is appropriate for
realizing those requirements, before trying to conduct any assessments of
compliance with principles or criteria. And then, the assessments must be
taken for what they are worth -- just one piece of the puzzle -- rather
than overendowed as definitive results out of context. Overall, there is
absolutely no substitute for human intelligence, experience, and foresight.
The Saltzer-Schroeder principle of keeping things simple
is one of the most
popular and commonly cited. However, it can be extremely misleading when
espoused (as it commonly is) in reference to systems with critical
requirements for security, reliability,
survivability, real-time performance, and high assurance -- especially when
all of these requirements are necessary within the same system environment.
Simplicity is a very important concept in principle (in the small), but
complexity is often unavoidable in practice (in the large). For example,
serious attempts to achieve fault-tolerant behavior often result in roughly
doubling the size of the overall subsystem or even the entire system. As a
result, the principle of simplicity should really be one of managing
complexity rather than trying to eliminate
it, particularly where complexity is in fact inherent in the combination of
requirements. Keeping things simple is indeed a conceptually wonderful
principle, but often not achievable in reality. Nevertheless, unnecessary complexity should of course be avoided. The back-side of the
Einstein quote at the beginning of Section 2.1 is indeed both
profound and relevant, yet often
overlooked in the overzealous quest for perceived
simplicity.
An extremely effective approach to dealing with intrinsic complexity is
through a combination of the principles discussed here, particularly
abstraction, modularity, encapsulation, and careful hierarchical separation that
architecturally does not result in serious performance penalties, well
conceived virtualized interfaces that greatly facilitate implementation
evolution without requiring changes to the interfaces or that enable design
evolution with minimal disruption, and far-sighted
optimization. In particular, hierarchical
abstraction can result in relative
simplicity at the interfaces of each abstraction and each layer, in relative
simplicity of the interconnections, and perhaps even relative simplicity in
the implementation of each module. By keeping the components and their
interconnections conceptually simple, it is possible to achieve conceptual
simplicity of the overall system or networks of systems despite inherent
complexity.
Furthermore, simplicity can sometimes be achieved through
design generality, recognizing that several seemingly different problems can
be solved symmetrically at the same time, rather than creating different
(and perhaps incompatible) solutions. Such approaches are considered further
in Chapter 4.
Note that such solutions might appear
to be a violation of the principle of least common mechanism, but not when
the common mechanism is fundamental -- as in the use of a single uniform
naming convention or the use of a uniform addressing mode that transcends
different subtypes of typed objects. In general, it is riskful to have
multiple procedures managing the same data structure for the same purposes.
However, it can be very beneficial to separate reading from writing -- as
in the case of one process that updates and another process that uses the
data. It can also be beneficial to reuse the same code on different data
structures, although strong typing is then important.
Of considerable interest here is David Musser's notion of Generic
Programming, or programming with concepts. His Web site defines a concept as "a family of abstractions that are all related by a common set
of requirements. A large part of the activity of generic programming,
particularly in the design of generic software components, consists of
concept development -- identifying sets of requirements that are general
enough to be met by a large family of abstractions but still restrictive
enough that programs can be written that work efficiently with all members
of the family. The importance of the C++ Standard Template Library, STL,
lies more in its concepts than in the actual code or the details of its
interfaces."
(http://www.cs.rpi.edu/ musser/gp/)
One of our primary goals in this project is to make system interfaces
conceptually simple while masking complexity so that the complexities of the design process and the
implementation itself can be hidden by the interfaces. This may in fact
increase the complexity of the desContents
Preface
Abstract
Executive Summary
Anyone will renovate his science who will steadily look after
the irregular phenomena. And when the science is renewed, its new formulas
often have more of the voice of the exceptions in them than of what were
supposed to be the rules.
William James
Roadmap of This Report
1 The Foundations of This Report
We essay a difficult task; but there is no merit save in
difficult tasks.
Ovid
2 Fundamental Principles of Trustworthiness
Synopsis
2.1 Introduction
Everything should be made as simple as possible -- but no simpler.
Albert Einstein
2.2 Risks Resulting from Untrustworthiness
2.3 Trustworthiness Principles
Willpower is always more efficient than mechanical enforcement,
when it works. But there is always a size of system beyond
which willpower will be inadequate.
Butler Lampson
2.3.1 Saltzer-Schroeder Security Principles, 1975
*
Economy of mechanism: Seek design simplicity (wherever and
to whatever extent it is effective).
*
Fail-safe defaults: Deny accesses unless explicitly authorized
(rather than permitting accesses unless explicitly denied).
*
Complete mediation: Check every access, without exception.
*
Open design: Do not assume that design secrecy will enhance security.
*
Separation of privileges: Use separate privileges or even
multiparty authorization (e.g., two keys) to reduce misplaced trust.
*
Least privilege: Allocate
minimal (separate) privileges according to
need-to-know, need-to-modify, need-to-delete, need-to-use, and so on. The
existence of overly powerful mechanisms such as superuser is inherently dangerous.
*
Least common mechanism:
Minimize the amount of mechanism common to more than one user
and depended on by all users.
Avoid sharing of trusted multipurpose
mechanisms, including executables and data
-- in particular, minimizing the need for and
use of overly powerful mechanisms such as superuser
and FORTRAN common. As one
example of the flaunting of this principle,
exhaustion of shared resources provides a huge source of covert
storage channels,
whereas the natural sharing of real calendar-clock time provides
a source of covert timing channels.
*
Psychological acceptability: Strive for ease of use and operation --
for example, with easily understandable and forgiving interfaces.
*
Work factor: Make cost-to-protect commensurate with threats
and expected risks.
*
Recording of compromises:
Provide nonbypassable tamperproof trails of evidence.
Principle Composability Trustworthiness Assurance
Economy of Beneficial within a sound Vital aid to sound Can simplify
mechanism architecture; requires design; exceptions must analysis
proactive design effort be completely handled
Fail-safe Some help, but not Simplifies design, Can simplify
defaults fundamental use, operation analysis
Complete Very beneficial with Vital, but hard Can simplify
mediation disjoint object types to achieve with no analysis
compromisibility
Open design Design documentation is Secrecy of design is, Assurance is mostly
very beneficial among a bad assumption; irrelevant in badly
multiple developers open design requires designed systems;
strong system security open design enables
open analysis (+/-)
Separation of Very beneficial if Avoids many Focuses analysis
privileges preserved by composition common flaws more precisely
Least Very beneficial if Limits flaw effects; Focuses analysis
privilege preserved by composition simplifies operation more precisely
Least common Beneficial unless there is Finesses some Modularizes
mechanism natural polymorphism common flaws analysis
Psychological Could help a little -- Affects mostly usability Ease of use
acceptability if not subvertible and operations can contribute
Work factor Relevant especially for Misguided if system Gives false sense
crypto algorithms, but not easily compromised of security under
their implementations; from below, spoofed, nonalgorithmic
may not be composable bypassed, etc. compromises
Compromise Not an impediment After-the-fact, Not primary
recording if distributed; real-time but useful contributor
detection/response needs
must be anticipated
http://www.cl.cam.ac.uk/users/rja14/
2.3.2 Related Principles, 1969 and Later
At this point in our analysis, it should be no surprise that all of these
principles can contribute in varying ways to security, reliability,
survivability, and other -ilities. Furthermore, many of the principles and
-ilities are linked. We cite just a few of the interdependencies that must
be considered.
Principle Composability Trustworthiness Assurance
Sound Can considerably Can greatly increase Can increase assurance
architecture facilitate composition trustworthiness of design and simplify
implementation analysis
Minimization of Beneficial, but not Very beneficial with Simplifies design and
trustworthiness fundamental sound architecture implementation analysis
Abstraction Very beneficial with Very beneficial Simplifies analysis
suitable independence if composable by decoupling it
Encapsulation Very beneficial Very beneficial if Localizes analysis to
if properly done, composable, avoids abstractions and
enhances integration certain types of bugs their interactions
Modularity Very beneficial Very beneficial Simplifies analysis
if interfaces and if well specified; by decoupling it
specifications overmodularization and if modules are
well defined impairs performance well specified
Layered protection Very beneficial, but Very beneficial if Structures analysis
may impair noncompromisible from according to layers
performance above/within/below and their interactions
Robust dependency Beneficial: can Beneficial: can obviate Robust
architectural
avoid compositional design flaws based on structure simplifies
conflicts misplaced trust analysis
Object orientation Beneficial, but Can be beneficial, but Can simplify analysis
labor-intensive; complicates coding of design, possibly
can be inefficient and debugging implementation also
Separation of Beneficial, but Increases flexibility Simplifies analysis
policy/mechanism both must compose and evolution
Separation of Helpful indirectly Beneficial if Can simplify analysis
duties as a precursor well defined if well defined
Separation of Beneficial if roles Beneficial if Partitions analysis
roles nonoverlapping properly enforced of design and operation
Separation of Can simplify Allows finer-grain Partitions analysis
domains composition and enforcement and of implementation
reduce side effects self-protection and operation
Sound Helps if uniformly Huge security benefits, Can simplify analysis,
authentication invoked aids accountability improve assurance
Sound Helps if uniformly Controls use, Can simplify analysis,
authorization invoked aids accountability improve assurance
Administrative Composability helps Good architecture Control enhances
controllability controllability helps controllability operational assurance
Comprehensive Composability helps Beneficial for Can provide feedback
accountability accountability post-hoc analysis for improved assurance
2.3.3 Principles of Secure Design (NSA, 1993)
2.3.4 Generally Accepted Systems Security Principles (I2F, 1997)
Pervasive Principles
* PP-1. Accountability
* PP-2. Awareness
* PP-3. Ethics
* PP-4. Multidisciplinary
* PP-5. Proportionality
* PP-6. Integration
* PP-7. Timeliness
* PP-8. Assessment
* PP-9. Equity
Broad Functional Principles
* BFP-1. Information Security
* BFP-2. Education and Awareness
* BFP-3. Accountability
* BFP-4. Information Management
* BFP-5. Environmental Management
* BFP-6. Personnel Qualifications
* BFP-7. System Integrity
* BFP-8. Information Systems Life Cycle
* BFP-9. Access Control
* BFP-10. Operational Continuity and Contingency Planning
* BFP-11. Information Risk Management
* BFP-12. Network and Infrastructure Security
* BFP-13. Legal, Regulatory, and Contractual Requirements of Info Security
* BFP-14. Ethical Practices
PP: PP-1 PP-2 PP-3 PP-4 PP-5 PP-6 PP-7 PP-8 PP-9
BFP-1 X X X X X X X X X
BFP-2 X X X X X
BFP-3 X X X X X
BFP-4 X X X X
BFP-5 X X X X X X
BFP-6 X X X X
BFP-7 X X X X X X
BFP-8 X X X X X X
BFP-9 X X X X X X
BFP-10 X X X X X
BFP-11 X X X X X X X
BFP-12 X X X X X
BFP-13 X X X X X
BFP-14 X X X X
2.3.5 TCSEC, ITSEC, CTCPEC, and the Common Criteria (1985 to date)
2.3.6 Extreme Programming, 1999
2.3.7 Other Approaches to Principled Development
2.4 Design and Implementation Flaws, and Their
Avoidance
Nothing is as simple as we hope it will be. Jim Horning
2.5 Roles of Assurance and Formalism
In principle, everything should be simple.
In reality, things are typically not so simple.
(Note: The SRI CSL Principal Scientist is evidently both a
Principle Scientist and a Principled Scientist,
as well as Principal Scientist. PGN)
2.6 Caveats on Applying the Principles
For every complex problem, there is a simple solution.
And it's always wrong.
H.L. Mencken