Shall, Should, and May

September 16th, 2007

The text of RFC2119, which describes the use of these phrases in system documentation, is presented here:

Network Working Group
Request for Comments: 2119
BCP: 14
Category: Best Current Practice

S. Bradner
Harvard University
March 1997

— Status of this Memo —
This document specifies an Internet Best Current Practices for the
Internet Community, and requests discussion and suggestions for
improvements. Distribution of this memo is unlimited.

— Abstract —
In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. Authors who follow these guidelines should incorporate this phrase near the beginning of their document:

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

Note that the force of these words is modified by the requirement level of the document in which they are used.

1. MUST — This word, or the terms “REQUIRED” or “SHALL”, mean that the definition is an absolute requirement of the specification.

2. MUST NOT — This phrase, or the phrase “SHALL NOT”, mean that the definition is an absolute prohibition of the specification.

3. SHOULD — This word, or the adjective “RECOMMENDED”, mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.

4. SHOULD NOT — This phrase, or the phrase “NOT RECOMMENDED” mean that there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood and the case carefully weighed before implementing any behavior described with this label.

5. MAY — This word, or the adjective “OPTIONAL”, mean that an item is truly optional. One vendor may choose to include the item because a particular marketplace requires it or because the vendor feels that it enhances the product while another vendor may omit the same item. An implementation which does not include a particular option MUST be prepared to interoperate with another implementation which does include the option, though perhaps with reduced functionality. In the same vein an implementation which does include a particular option MUST be prepared to interoperate with another implementation which does not include the option (except, of course, for the feature the option provides.)

6. Guidance in the use of these Imperatives
Imperatives of the type defined in this memo must be used with care and sparingly. In particular, they MUST only be used where it is actually required for interoperation or to limit behavior which has potential for causing harm (e.g., limiting retransmisssions) For example, they must not be used to try to impose a particular method on implementors where the method is not required for interoperability.

7. Security Considerations
These terms are frequently used to specify behavior with security implications. The effects on security of not implementing a MUST or SHOULD, or doing something the specification says MUST NOT or SHOULD NOT be done may be very subtle. Document authors should take the time to elaborate the security implications of not following recommendations or requirements as most implementors will not have had the benefit of the experience and discussion that produced the specification.

8. Acknowledgments
The definitions of these terms are an amalgam of definitions taken from a number of RFCs. In addition, suggestions have been incorporated from a number of people including Robert Ullmann, Thomas Narten, Neal McBurnett, and Robert Elz.

9. Author’s Address
Scott Bradner
Harvard University
1350 Mass. Ave.
Cambridge, MA 02138
phone – +1 617 495 3864
email – sob@harvard.edu

Secure Coding: Principles & Practices

August 28th, 2007

31a4xgqm9dl_aa_sl160_.jpgI read Graff and van Wyk’s Secure Coding: Principles & Practices to completion, but not because each page was more enlightening than the previous. I realized that the same themes and adages were being repeated constantly after having read half the book. Because it was pretty easy to get midway through the book, I decided on continuing through it for the sake of completeness. As critical as I can be about the book, there are characteristics of the book that may be redeeming.

The lessons that the authors attempt to convey seem to be an extension of what is taught in a typical software engineering course. Being about security, the book suggests that software engineers keep security concerns in mind while proceeding through a development life cycle. While testing and designing, the book suggests without going into specifics, software engineers should think about ways that other entities may try to subvert their application systems. The authors encourage implementing systems with a high degree of visibility, accountability, and traceability. They also stress the need to consider the security of an application’s target environment. Normal review of the a and testing of an implementation during a software development life cycle should already address security concerns. The book serves to make this point explicit.

The authors’ principal ideas are repeated throughout the book. Perhaps, the authors believe that people retain about 10% on average of the information that comes to them, and the authors feel they need to repeat their lesson at least ten times to guarantee its reception. The book should not be discounted as a waste of time. After all, the stories, other than the same SYN flood and buffer overrun examples that are used throughout the book, were fairly entertaining.

On the Lack of Exceptions

August 9th, 2007

Lately, I’ve been helping develop a reasonably sized application, which detects errors at every operation. Checking the return value of every function call seems awkward when compared to code that is written in rather informal working environments. Writing code that checks each return value is frustrating when a feature that exists in another language is not available in the current implementation language. A function signature that may allow for the detection of a function’s failure is as follows:

STATUS operation( ArgType1 arg1, ArgTypeN argN );

The only qualm I have with the above function signature is that operation() is inconsistent with the mathematical notion of a function. Instead of having y = f(x), where the parameters to f() are unchanged, the function signature above has a return value set of {SUCCESS,!SUCCESS}, and the result of the operation may be stored at a memory location that is passed as an “out” parameter. Although operation() is less function-like, I like this method more than the use of global variables and additional function calls for error checking.

An apparent problem, or nuisance, occurs when multiple calls to operation() are made and error checking with handling needs to be performed. The code becomes saturated with conditionals and possible duplication of error handling code:


if( SUCCESS != operation(arg1,arg2) )
{
	/* error_handling_code_1 */
}

/* omitted_code_1 */

if( SUCCESS != operation(arg3,arg4) )
{
	/* error_handling_code_1 */
}

/* ommitted_code_2 */

if( SUCCESS != operation(arg4,arg5) )
{
	/* error_handling_code_1 */
}

This situation is just screaming for the use of exceptions. Exceptions would allow the code to be easier to read, and the implementation of the error handling code can be more disjoint from the function call that is experiencing the error.


try
{
	operation(arg1,arg2);
	/* ommitted_code_1 */
	operation(arg3,arg4);
	/* ommitted_code_2 */
	operation(arg4,arg5);
}
catch( ExceptionType1 arg )
{
	/* error_handling_code_1 */
}
catch( ... )
{
	/* if a given exception is not handled here, */
	/* it may be possible to rethrow the exception */
}

Although the target system might not have exception support, having to implement the discussed code helped me appreciate exceptions.

Transitions

July 14th, 2007

Transitions are always difficult.

While in Deutschland

June 18th, 2007

bundesflagge.gifI have been at Germany for two weeks out of the last month. I took on a task that I thought was theoretically possible, but one where completion under given time and resource allocation constraints was uncertain. The situation called for code developed in a proprietary environment for many months by many people to be ported to another proprietary environment. I took advantage of several software engineering methods, many that I have read about and adopted, to bring about success.

Success in this task was based on several factors that were set in the past. Many of these factors were not and could not be influenced by me. For example, the decision to adopt a highly portable programming language was crucial in the success and ease of the porting effort. Development of the code base started long before I joined the team, and I am glad that the team was steered toward the currently used programming language. Porting an application that is implemented in Visual Basic to a Unix-like environment seems more daunting or even impossible than porting a program that is implemented in C from a Microsoft Windows environment to a Linux environment.

The power of abstraction, interfaces, and separation of concerns were evident in the somewhat rushed porting effort. A well-defined interface of the source environment eased the implementation of the interface within the destination environment. Porting the code was a task of implementing the code’s functional dependencies. After the porting effort was completed, any and all code that is implemented for the source environment could be introduced to the target environment with little to no changes.

I tapped the help of several specialists of different facets of the code base. Specialists of the tools were also helpful. Without their help, the porting effort would have failed. Two weeks is simply not enough time to learn all the details of the code base and source environment, and implement the needed constructs on the target environment. People provided assistance in the form of functional implementation, problem diagnosis, and code examples. We brought about success together. This effort has provided me with a lot of experience, and I hope to find time to write up a couple of postmortems and share the methods that I used to help bring about success.