CDRL A001 Final Report December 28, 2004

Principled Assuredly Trustworthy
Composable Architectures
 
Final Report
Contract number N66001-01-C-8040
DARPA Order No. M132
SRI Project P11459

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

Contents

  • Contents
  • Preface
  • Abstract
  • Executive Summary
  • Roadmap of This Report
  • 1 The Foundations of This Report
  • 2 Fundamental Principles of Trustworthiness
  • Synopsis
  • 2.1 Introduction
  • 2.2 Risks Resulting from Untrustworthiness
  • 2.3 Trustworthiness Principles
  • 2.3.1 Saltzer-Schroeder Security Principles, 1975
  • 2.3.2 Related Principles, 1969 and Later
  • 2.3.3 Principles of Secure Design (NSA, 1993)
  • 2.3.4 Generally Accepted Systems Security Principles (I2F, 1997)
  • 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
  • 2.5 Roles of Assurance and Formalism
  • 2.6 Caveats on Applying the Principles
  • 2.7 Summary
  • 3 Realistic Composability
  • Synopsis
  • 3.1 Introduction
  • 3.2 Obstacles to Seamless Composability
  • 3.3 System Decomposition
  • 3.4 Attaining Facile Composability
  • 3.5 Paradigmatic Mechanisms for Enhancing Trustworthiness
  • 3.6 Enhancing Trustworthiness in Real Systems
  • 3.7 Challenges
  • 3.8 Summary
  • 4 Principled Composable Trustworthy Architectures
  • Synopsis
  • 4.1 Introduction
  • 4.2 Realistic Application of Principles
  • 4.3 Principled Architecture
  • 4.4 Examples of Principled Architectures
  • 4.5 Openness Paradigms
  • 4.6 Summary
  • 5 Principled Interface Design
  • Synopsis
  • 5.1 Introduction
  • 5.2 Fundamentals
  • 5.2.1 Motivations for Focusing on Perspicuity
  • 5.2.2 Risks of Bad Interfaces
  • 5.2.3 Desirable Characteristics of Perspicuous Interfaces
  • 5.2.4 Basic Approaches
  • 5.2.5 Perspicuity Based on Behavioral Specifications
  • 5.2.6 System Modularity, Visibility, Control, and Correctness
  • 5.3 Perspicuity through Synthesis
  • 5.3.1 System Architecture
  • 5.3.2 Software Engineering
  • 5.3.3 Programming Languages and Compilers
  • 5.3.4 Administration and System Operation
  • 5.3.5 No More and No Less
  • 5.3.6 Multilevel Security and Capabilities
  • 5.4 Perspicuity through Analysis
  • 5.4.1 General Needs
  • 5.4.2 Formal Methods
  • 5.4.3 Ad-Hoc Methods
  • 5.4.4 Hybrid Approaches
  • 5.4.5 Inadequacies of Existing Techniques
  • 5.5 Pragmatics
  • 5.5.1 Illustrative Worked Examples
  • 5.5.2 Contemplation of a Specific Example
  • 5.6 Conclusions
  • 6 Assurance
  • Synopsis
  • 6.1 Introduction
  • 6.2 Foundations of Assurance
  • 6.3 Approaches to Increasing Assurance
  • 6.4 Formalizing System Design and Development
  • 6.5 Implementation Consistency with Design
  • 6.6 Static Code Analysis
  • 6.7 Real-Time Code Analysis
  • 6.8 Metrics for Assurance
  • 6.9 Assurance-Based Risk Reduction
  • 6.10 Conclusions on Assurance
  • 7 Practical Considerations
  • Synopsis
  • 7.1 Risks of Short-Sighted Optimization
  • 7.2 The Importance of Up-Front Efforts
  • 7.3 The Importance of Whole-System Perspectives
  • 7.4 The Development Process
  • 7.4.1 Disciplined Requirements
  • 7.4.2 Disciplined Architectures
  • 7.4.3 Disciplined Implementation
  • 7.5 Disciplined Operational Practice
  • 7.5.1 Today's Overreliance on Patch Management
  • 7.5.2 Architecturally Motivated System Administration
  • 7.6 Practical Priorities for Perspicuity
  • 7.7 Assurance Throughout Development
  • 7.7.1 Disciplined Analysis of Requirements
  • 7.7.2 Disciplined Analysis of Design and Implementation
  • 7.8 Assurance in Operational Practice
  • 7.9 Certification
  • 7.10 Management Practice
  • 7.10.1 Leadership Issues
  • 7.10.2 Pros and Cons of Outsourcing
  • 7.11 A Forward-Looking Retrospective
  • 8 Recommendations for the Future
  • 8.1 Introduction
  • 8.2 General R&D Recommendations
  • 8.3 Some Specific Recommendations
  • 8.4 Architectures with Perspicuous Interfaces
  • 8.5 Other Recommendations
  • 9 Conclusions
  • 9.1 Summary of This Report
  • 9.2 Summary of R&D Recommendations
  • 9.3 Risks
  • 9.4 Concluding Remarks
  • Acknowledgments
  • A Formally Based Static Analysis (Hao Chen)
  • A.1 Goals of the Berkeley Subcontract
  • A.2 Results of the Berkeley Subcontract
  • A.3 Recent Results
  • A.4 Integration of Static Checking into EMERALD
  • B System Modularity (Virgil Gligor)
  • B.1 Introduction
  • B.2 Modularity
  • B.2.1 A Definition of "Module" for a Software System
  • B.2.2 System Decomposition into Modules
  • B.2.3 The "Contains" Relation
  • B.2.4 The "Uses" Relation
  • B.2.5 Correctness Dependencies Among System Modules
  • B.2.6 Using Dependencies for Structural Analysis of Software Systems
  • B.3 Module Packaging
  • B.4 Visibility of System Structure Using Modules
  • B.4.1 Design Abstractions within Modules
  • B.4.2 Information Hiding as a Design Abstraction for Modules
  • B.4.3 Layering as a Design Abstraction Using Modules
  • B.5 Measures of Modularity and Module Packaging
  • B.5.1 Replacement Dependence Measures
  • B.5.2 Global Variable Measures
  • B.5.3 Module Reusability Measures
  • B.5.4 Component-Packaging Measures
  • B.6 Cost Estimates for Modular Design
  • B.7 Tools for Modular Decomposition and Evaluation
  • B.7.1 Modularity Analysis Tools Based on Clustering
  • B.7.2 Modularity Analysis Tools based on Concept Analysis
  • B.8 Virgil Gligor's Acknowledgments
  • References
  • Index
  • Preface

    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.

    Abstract

    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.

    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 

    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).

    Roadmap of This Report

    The outline of this report is as follows.

    1 The Foundations of This Report

    We essay a difficult task; but there is no merit save in difficult tasks.
    Ovid 

    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.

    2 Fundamental Principles of Trustworthiness

    Synopsis

    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.

    2.1 Introduction

    Everything should be made as simple as possible -- but no simpler.
    Albert Einstein 

    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". 

    2.2 Risks Resulting from Untrustworthiness

    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.

    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  

    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.

    2.3.1 Saltzer-Schroeder Security Principles, 1975

    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:

    * 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.

    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).


    Table 1: CHATS Relevance of Saltzer-Schroeder to CHATS Goals
     
    PrincipleComposabilityTrustworthinessAssurance
    Economy of Beneficial within a soundVital aid to soundCan simplify
    mechanism architecture; requires design; exceptions mustanalysis
    proactive design effortbe 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 typesto achieve with noanalysis
    compromisibility
    Open designDesign documentation isSecrecy of design is,Assurance is mostly
    very beneficial amonga bad assumption;irrelevant in badly
    multiple developersopen design requires designed systems;
    strong system securityopen design enables
    open analysis (+/-)
    Separation of Very beneficial if Avoids many Focuses analysis
    privileges preserved by compositioncommon 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 subvertibleand operations can contribute
    Work factor Relevant especially forMisguided if systemGives false sense
    crypto algorithms, but noteasily compromisedof security under
    their implementations;from below, spoofed,nonalgorithmic
    may not be composable bypassed, etc. compromises
    Compromise Not an impedimentAfter-the-fact, Not primary
    recording if distributed; real-timebut useful contributor
    detection/response needs
    must be anticipated

    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:  
    http://www.cl.cam.ac.uk/users/rja14/

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

    2.3.2 Related Principles, 1969 and Later

    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.


    Table 2: CHATS Relevance of Extended-Set Principles to CHATS Goals
     
    PrincipleComposabilityTrustworthinessAssurance
    Sound Can considerablyCan greatly increaseCan increase assurance
    architecture facilitate compositiontrustworthinessof design and simplify
    implementation analysis
    Minimization ofBeneficial, but notVery beneficial withSimplifies design and
    trustworthinessfundamental sound architectureimplementation analysis
    Abstraction Very beneficial withVery beneficial Simplifies analysis
    suitable independenceif composable by decoupling it
    Encapsulation Very beneficial Very beneficial if Localizes analysis to
    if properly done,composable, avoids abstractions and
    enhances integrationcertain types of bugs their interactions
    Modularity Very beneficial Very beneficial Simplifies analysis
    if interfaces andif well specified;by decoupling it
    specifications overmodularizationand if modules are
    well defined impairs performancewell specified
    Layered protectionVery beneficial, butVery beneficial ifStructures analysis
    may impairnoncompromisible fromaccording to layers
    performance above/within/belowand their interactions
    Robust dependencyBeneficial: canBeneficial: can obviateRobust architectural
    avoid compositionaldesign flaws based onstructure simplifies
    conflicts misplaced trustanalysis
    Object orientationBeneficial, butCan be beneficial, butCan simplify analysis
    labor-intensive; complicates coding of design, possibly
    can be inefficientand debuggingimplementation also
    Separation of Beneficial, but Increases flexibilitySimplifies analysis
    policy/mechanismboth must composeand evolution
    Separation of Helpful indirectly Beneficial if Can simplify analysis
    duties as a precursor well defined if well defined
    Separation of Beneficial if rolesBeneficial if Partitions analysis
    roles nonoverlapping properly enforced of design and operation
    Separation of Can simplify Allows finer-grainPartitions analysis
    domains composition and enforcement and of implementation
    reduce side effectsself-protection and operation
    Sound Helps if uniformlyHuge security benefits,Can simplify analysis,
    authentication invoked aids accountability improve assurance
    Sound Helps if uniformlyControls use, Can simplify analysis,
    authorization invoked aids accountability improve assurance
    Administrative Composability helpsGood architectureControl enhances
    controllabilitycontrollability helps controllabilityoperational assurance
    Comprehensive Composability helpsBeneficial for Can provide feedback
    accountability accountabilitypost-hoc analysis for improved assurance

    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.  

    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?)

    2.3.3 Principles of Secure Design (NSA, 1993)

    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.

    2.3.4 Generally Accepted Systems Security Principles (I2F, 1997)

    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.

    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

    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.


    Table 3: GASSP Cross-Impact Matrix
     
    PP: PP-1PP-2PP-3PP-4PP-5PP-6PP-7PP-8PP-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)

    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.)

    2.3.6 Extreme Programming, 1999

    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 ).

    2.3.7 Other Approaches to Principled 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.

    2.4 Design and Implementation Flaws, and Their Avoidance

    Nothing is as simple as we hope it will be. Jim Horning  

    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.

     

    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) 

    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.

    2.6 Caveats on Applying the Principles

    For every complex problem, there is a simple solution. And it's always wrong.
    H.L. Mencken 

    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 des