first pass at an Antora conversion

This commit is contained in:
Brian (bex) Exelbierd 2018-09-20 11:29:31 +02:00
parent 2e8934be40
commit f7cf94cd4c
193 changed files with 246 additions and 29224 deletions

View file

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.0"
width="220"
height="70"
id="svg6180">
<defs
id="defs6182" />
<g
transform="translate(-266.55899,-345.34488)"
id="layer1">
<path
d="m 316.7736,397.581 c 0,0 0,0 -20.53889,0 0.3327,4.45245 3.92157,7.77609 8.70715,7.77609 3.38983,0 6.31456,-1.39616 8.64094,-3.65507 0.46553,-0.46679 0.99726,-0.59962 1.59519,-0.59962 0.79781,0 1.59561,0.39932 2.12692,1.06388 0.3327,0.46553 0.53216,0.99726 0.53216,1.52857 0,0.73118 -0.3327,1.52857 -0.93106,2.12734 -2.7919,2.99052 -7.51086,4.98503 -12.16403,4.98503 -8.44149,0 -15.22074,-6.77967 -15.22074,-15.22158 0,-8.44149 6.58022,-15.22074 15.02171,-15.22074 8.37529,0 14.62323,6.51317 14.62323,15.08749 0,1.26418 -1.12924,2.12861 -2.39258,2.12861 z m -12.23065,-11.76512 c -4.45329,0 -7.51085,2.92473 -8.17499,7.17731 10.03626,0 16.35083,0 16.35083,0 -0.59836,-4.05355 -3.78874,-7.17731 -8.17584,-7.17731 z"
id="path11"
style="fill:#3c6eb4" />
<path
d="m 375.46344,410.80807 c -8.44106,0 -15.22074,-6.77968 -15.22074,-15.22159 0,-8.44149 6.77968,-15.22074 15.22074,-15.22074 8.44234,0 15.22159,6.77925 15.22159,15.22074 -4.2e-4,8.44149 -6.77968,15.22159 -15.22159,15.22159 z m 0,-24.65992 c -5.31688,0 -8.77377,4.25427 -8.77377,9.43833 0,5.18364 3.45689,9.43833 8.77377,9.43833 5.31731,0 8.77504,-4.25469 8.77504,-9.43833 -4.2e-4,-5.18406 -3.45773,-9.43833 -8.77504,-9.43833 z"
id="path13"
style="fill:#3c6eb4" />
<path
d="m 412.66183,380.36574 c -4.45963,0 -7.40966,1.319 -10.01391,4.62956 l -0.24036,-1.53995 0,0 c -0.20198,-1.60743 -1.57326,-2.84926 -3.23382,-2.84926 -1.80139,0 -3.26206,1.459 -3.26206,3.26081 0,0.003 0,0.005 0,0.008 l 0,0 0,0.003 0,0 0,23.40712 c 0,1.79464 1.46194,3.25743 3.257,3.25743 1.79465,0 3.25744,-1.46279 3.25744,-3.25743 l 0,-12.56209 c 0,-5.71621 4.98502,-8.57432 10.23613,-8.57432 1.59519,0 2.85726,-1.32953 2.85726,-2.92515 0,-1.59561 -1.26207,-2.85726 -2.85768,-2.85726 z"
id="path15"
style="fill:#3c6eb4" />
<path
d="m 447.02614,395.58648 c 0.0666,-8.17541 -5.78326,-15.22074 -15.222,-15.22074 -8.44192,0 -15.28779,6.77925 -15.28779,15.22074 0,8.44191 6.64684,15.22159 14.68985,15.22159 4.01434,0 7.62682,-2.06621 9.23846,-4.22518 l 0.79359,2.01434 0,0 c 0.42589,1.13177 1.5176,1.93717 2.7978,1.93717 1.65001,0 2.98756,-1.33671 2.99009,-2.98545 l 0,0 0,-7.80687 0,0 0,-4.1556 z m -15.222,9.43833 c -5.31773,0 -8.77419,-4.25469 -8.77419,-9.43833 0,-5.18406 3.45604,-9.43833 8.77419,-9.43833 5.3173,0 8.77419,4.25427 8.77419,9.43833 0,5.18364 -3.45689,9.43833 -8.77419,9.43833 z"
id="path17"
style="fill:#3c6eb4" />
<path
d="m 355.01479,368.3337 c 0,-1.7938 -1.46194,-3.18997 -3.25659,-3.18997 -1.79422,0 -3.25743,1.39659 -3.25743,3.18997 l 0,17.1499 c -1.66097,-3.05756 -5.25026,-5.11786 -9.50495,-5.11786 -8.64052,0 -14.42336,6.51318 -14.42336,15.22074 0,8.70757 5.98229,15.22159 14.42336,15.22159 3.76555,0 7.03057,-1.55429 8.98587,-4.25554 l 0.72317,1.83428 c 0.44782,1.25912 1.64917,2.16024 3.06051,2.16024 1.78621,0 3.24984,-1.45435 3.24984,-3.24815 0,-0.005 0,-0.009 0,-0.0139 l 0,0 0,-38.95128 -4.2e-4,0 z m -15.22116,36.69111 c -5.31731,0 -8.70715,-4.25469 -8.70715,-9.43833 0,-5.18406 3.38984,-9.43833 8.70715,-9.43833 5.31773,0 8.70714,4.0544 8.70714,9.43833 0,5.38309 -3.38941,9.43833 -8.70714,9.43833 z"
id="path19"
style="fill:#3c6eb4" />
<path
d="m 287.21553,365.34023 c -0.59414,-0.0877 -1.19966,-0.13198 -1.80097,-0.13198 -6.73118,0 -12.20746,5.4767 -12.20746,12.20788 l 0,3.8132 -3.98903,0 c -1.46237,0 -2.65908,1.19671 -2.65908,2.65781 0,1.46321 1.19671,2.93738 2.65908,2.93738 l 3.98819,0 0,20.46004 c 0,1.79464 1.46236,3.25743 3.25658,3.25743 1.79507,0 3.25744,-1.46279 3.25744,-3.25743 l 0,-20.46004 4.40986,0 c 1.46194,0 2.65823,-1.47417 2.65823,-2.93738 0,-1.46152 -1.19629,-2.65823 -2.65823,-2.65823 l -4.40733,0 0,-3.8132 c 0,-3.13852 2.55323,-6.11469 5.69175,-6.11469 0.28294,0 0.56757,0.0211 0.84672,0.062 1.78031,0.26355 3.4358,-0.54269 3.70019,-2.32342 0.2627,-1.77904 -0.96606,-3.43538 -2.74594,-3.69935 z"
id="path21"
style="fill:#3c6eb4" />
<path
d="m 482.01243,363.57426 c 0,-10.06788 -8.16108,-18.22938 -18.22897,-18.22938 -10.06282,0 -18.22179,8.15475 -18.22854,18.21631 l -4.2e-4,-4.2e-4 0,14.1071 4.2e-4,4.2e-4 c 0.005,2.28463 1.85832,4.13409 4.14463,4.13409 0.007,0 0.0127,-8.4e-4 0.0194,-8.4e-4 l 0.001,8.4e-4 14.07083,0 0,0 c 10.06409,-0.004 18.22138,-8.16276 18.22138,-18.22812 z"
id="path25"
style="fill:#294172" />
<path
d="m 469.13577,349.66577 c -4.72528,0 -8.55576,3.83049 -8.55576,8.55577 0,0.002 0,0.004 0,0.006 l 0,4.52836 -4.51444,0 c -8.5e-4,0 -8.5e-4,0 -0.001,0 -4.72528,0 -8.55576,3.81193 -8.55576,8.53678 0,4.72528 3.83048,8.55577 8.55576,8.55577 4.72486,0 8.55534,-3.83049 8.55534,-8.55577 0,-0.002 0,-0.004 0,-0.006 l 0,-4.54733 4.51444,0 c 8.5e-4,0 0.001,0 0.002,0 4.72486,0 8.55534,-3.79296 8.55534,-8.51781 0,-4.72528 -3.83048,-8.55577 -8.55534,-8.55577 z m -8.55576,21.63483 c -0.004,2.48998 -2.02446,4.50811 -4.51571,4.50811 -2.49378,0 -4.53426,-2.02193 -4.53426,-4.5157 0,-2.49421 2.04048,-4.55366 4.53426,-4.55366 0.002,0 0.004,4.2e-4 0.006,4.2e-4 l 3.86971,0 c 0.001,0 0.002,-4.2e-4 0.003,-4.2e-4 0.35209,0 0.63799,0.28505 0.63799,0.63715 0,4.2e-4 -4.2e-4,8.4e-4 -4.2e-4,0.001 l 0,3.92284 -4.2e-4,0 z m 8.55534,-8.5448 c -0.001,0 -0.003,0 -0.004,0 l -3.87223,0 c -8.4e-4,0 -0.002,0 -0.002,0 -0.35252,0 -0.63757,-0.28506 -0.63757,-0.63758 l 0,-4.2e-4 0,-3.90343 c 0.004,-2.49083 2.02446,-4.50854 4.51571,-4.50854 2.49378,0 4.53468,2.02193 4.53468,4.51613 4.2e-4,2.49336 -2.04048,4.53384 -4.53426,4.53384 z"
id="path29"
style="fill:#3c6eb4" />
<path
d="m 460.58001,362.7558 0,-4.52836 c 0,-0.002 0,-0.004 0,-0.006 0,-4.72528 3.83048,-8.55577 8.55576,-8.55577 0.71685,0 1.22623,0.0805 1.88952,0.25469 0.96774,0.25385 1.75796,1.04618 1.75838,1.96922 4.2e-4,1.11575 -0.80919,1.92621 -2.0194,1.92621 -0.57642,0 -0.78473,-0.11048 -1.62892,-0.11048 -2.49125,0 -4.51149,2.01771 -4.51571,4.50854 l 0,3.90385 0,4.2e-4 c 0,0.35252 0.28505,0.63758 0.63757,0.63758 4.3e-4,0 0.001,0 0.002,0 l 2.96521,0 c 1.10521,0 1.99747,0.88467 1.99832,1.99283 0,1.10816 -0.89353,1.99114 -1.99832,1.99114 l -3.60489,0 0,4.54733 c 0,0.002 0,0.004 0,0.006 0,4.72485 -3.83048,8.55534 -8.55534,8.55534 -0.71684,0 -1.22623,-0.0805 -1.88952,-0.25469 -0.96774,-0.25343 -1.75838,-1.04618 -1.7588,-1.9688 0,-1.11575 0.80919,-1.92663 2.01982,-1.92663 0.576,0 0.78473,0.11048 1.6285,0.11048 2.49125,0 4.51191,-2.01771 4.51613,-4.50811 0,0 0,-3.92368 0,-3.9241 0,-0.35168 -0.2859,-0.63673 -0.63799,-0.63673 -4.3e-4,0 -8.5e-4,0 -0.002,0 l -2.96521,-4.2e-4 c -1.10521,0 -1.99831,-0.88214 -1.99831,-1.9903 -4.3e-4,-1.11533 0.90238,-1.99367 2.01939,-1.99367 l 3.58339,0 0,0 z"
id="path31"
style="fill:#ffffff" />
<path
d="m 477.41661,378.55292 2.81558,0 0,0.37898 -1.18152,0 0,2.94935 -0.45254,0 0,-2.94935 -1.18152,0 0,-0.37898 m 3.26144,0 0.67101,0 0.84937,2.26496 0.85381,-2.26496 0.67102,0 0,3.32833 -0.43917,0 0,-2.9226 -0.85828,2.28279 -0.45255,0 -0.85827,-2.28279 0,2.9226 -0.43694,0 0,-3.32833"
id="text6223"
style="fill:#294172;enable-background:new" />
</g>
<path
d="m 181.98344,61.675273 2.81558,0 0,0.37898 -1.18152,0 0,2.94935 -0.45254,0 0,-2.94935 -1.18152,0 0,-0.37898 m 3.26144,0 0.67101,0 0.84937,2.26496 0.85381,-2.26496 0.67102,0 0,3.32833 -0.43917,0 0,-2.9226 -0.85828,2.28279 -0.45255,0 -0.85827,-2.28279 0,2.9226 -0.43694,0 0,-3.32833"
id="path2391"
style="fill:#294172;enable-background:new" />
</svg>

After

Width:  |  Height:  |  Size: 7.6 KiB

23
modules/ROOT/nav.adoc Normal file
View file

@ -0,0 +1,23 @@
* xref:index.adoc[Book Information]
* Programming Languages
** xref:programming-languages/C.adoc[The C Programming Language]
** xref:programming-languages/CXX.adoc[The C++ Programming&nbsp;Language]
** xref:programming-languages/Java.adoc[The Java Programming Language]
** xref:programming-languages/Python.adoc[The Python Programming Language]
** xref:programming-languages/Shell.adoc[Shell Programming and bash]
** xref:programming-languages/Go.adoc[The Go Programming Language]
** xref:programming-languages/Vala.adoc[The Vala Programming Language]
* Specific Programming Tasks
** xref:tasks/Tasks-Library_Design.adoc[Library Design]
** xref:tasks/Tasks-Descriptors.adoc[File Descriptor Management]
** xref:tasks/Tasks-File_System.adoc[File System Manipulation]
** xref:tasks/Tasks-Temporary_Files.adoc[Temporary Files]
** xref:tasks/Tasks-Processes.adoc[Processes]
** xref:tasks/Tasks-Serialization.adoc[Serialization and Deserialization]
** xref:tasks/Tasks-Cryptography.adoc[Cryptography]
** xref:tasks/Tasks-Packaging.adoc[RPM Packaging]
* Implementing Security Features
** xref:features/Features-Authentication.adoc[Authentication and Authorization]
** xref:features/Features-TLS.adoc[Transport Layer Security (TLS)]
** xref:features/Features-HSM.adoc[Hardware Security Modules and Smart Cards]
* xref:Revision_History.adoc[Revision History]

View file

@ -0,0 +1,60 @@
:experimental:
[[appe-Defensive_Coding-Revision_History]]
= Revision History
`1.5`:: Fri Dec 1 2017, Mirek Jahoda (mjahoda@redhat.com)
* First release in AsciiDoc
* Many updates in the crypto-related sections
* Grammar and typography fixes
`1.3-1`:: Mon Oct 13 2014, Florian Weimer (fweimer@redhat.com)
* Go: Mention default value handling in deserialization
* Shell: New chapter
`1.2-1`:: Wed Jul 16 2014, Florian Weimer (fweimer@redhat.com)
* C: Corrected the `strncat` example
* C: Mention mixed signed/unsigned comparisons
* C: Unsigned overflow checking example
* C++: `operator new[]` has been fixed in GCC
* C++: Additional material on `std::string`, iterators
* OpenSSL: Mention [command]`openssl genrsa` entropy issue
* Packaging: X.509 key generation
* Go, Vala: Add short chapters
* Serialization: Notes on fragmentation and reassembly
`1.1-1`:: Tue Aug 27 2013, Eric Christensen (sparks@redhat.com)
* Add a chapter which covers some Java topics.
* Deserialization: Warn about Java's java.beans.XMLDecoder.
* C: Correct the advice on array allocation
(link:++https://bugzilla.redhat.com/show_bug.cgi?id=995595++[bug 995595]).
* C: Add material on global variables.
`1.0-1`:: Thu May 09 2013, Eric Christensen (sparks@redhat.com)
* Added more C and C++ examples.
* TLS Client NSS: Rely on NSS 3.14 cipher suite defaults.
`0-1`:: Thu Mar 7 2013, Eric Christensen (sparks@redhat.com)
* Initial publication.

View file

@ -0,0 +1,23 @@
:experimental:
.Florian Weimer
*Red Hat*
Product Security Team
fweimer@redhat.com
.Nikos Mavrogiannopoulos
*Red Hat*
Crypto Team
nmav@redhat.com
.Robert Relyea
*Red Hat*
Crypto Team
rrelyea@redhat.com

View file

@ -0,0 +1,21 @@
:experimental:
Copyright {YEAR} {HOLDER}.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons AttributionShare Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at link:++http://creativecommons.org/licenses/by-sa/3.0/++[]. The original authors of this document, and Red Hat, designate the Fedora Project as the "Attribution Party" for purposes of CC-BY-SA. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, JBoss, MetaMatrix, Fedora, the Infinity Logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
For guidelines on the permitted uses of the Fedora trademarks, refer to link:++https://fedoraproject.org/wiki/Legal:Trademark_guidelines++[].
*Linux* is the registered trademark of Linus Torvalds in the United States and other countries.
*Java* is a registered trademark of Oracle and/or its affiliates.
*XFS* is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
*MySQL* is a registered trademark of MySQL AB in the United States, the European Union and other countries.
All other trademarks are the property of their respective owners.

View file

@ -0,0 +1,6 @@
:HOLDER: Red Hat, Inc
:YEAR: 2012-2018
:nbsp:

View file

@ -0,0 +1,17 @@
void report_overflow(void);
int
add(int a, int b)
{
int result = a + b;
if (a < 0 || b < 0) {
return -1;
}
// The compiler can optimize away the following if statement.
if (result < 0) {
report_overflow();
}
return result;
}

View file

@ -0,0 +1,13 @@
void report_overflow(void);
unsigned
add_unsigned(unsigned a, unsigned b)
{
unsigned sum = a + b;
if (sum < a) { // or sum < b
report_overflow();
}
return sum;
}

View file

@ -0,0 +1,10 @@
unsigned
mul(unsigned a, unsigned b)
{
if (b && a > ((unsigned)-1) / b) {
report_overflow();
}
return a * b;
}

View file

@ -0,0 +1,8 @@
static const char *const string_list[] = {
"first",
"second",
"third",
NULL
};

View file

@ -0,0 +1,45 @@
ssize_t
extract_strings(const char *in, size_t inlen, char **out, size_t outlen)
{
const char *inp = in;
const char *inend = in + inlen;
char **outp = out;
char **outend = out + outlen;
while (inp != inend) {
size_t len;
char *s;
if (outp == outend) {
errno = ENOSPC;
goto err;
}
len = (unsigned char)*inp;
++inp;
if (len > (size_t)(inend - inp)) {
errno = EINVAL;
goto err;
}
s = malloc(len + 1);
if (s == NULL) {
goto err;
}
memcpy(s, inp, len);
inp += len;
s[len] = '\0';
*outp = s;
++outp;
}
return outp - out;
err:
{
int errno_old = errno;
while (out != outp) {
free(*out);
++out;
}
errno = errno_old;
}
return -1;
}

View file

@ -0,0 +1,14 @@
void log_format(const char *format, ...) __attribute__((format(printf, 1, 2)));
void
log_format(const char *format, ...)
{
char buf[1000];
va_list ap;
va_start(ap, format);
vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
log_string(buf);
}

View file

@ -0,0 +1,10 @@
char buf[512];
char *current = buf;
const char *const end = buf + sizeof(buf);
for (struct item *it = data; it->key; ++it) {
snprintf(current, end - current, "%s%s=%d",
current == buf ? "" : ", ", it->key, it->value);
current += strlen(current);
}

View file

@ -0,0 +1,4 @@
char fraction[30];
snprintf(fraction, sizeof(fraction), "%d/%d", numerator, denominator);

View file

@ -0,0 +1,4 @@
buf[0] = '\0';
strncat(buf, data, sizeof(buf) - 1);

View file

@ -0,0 +1,5 @@
char buf[10];
snprintf(buf, sizeof(buf), "%s", prefix);
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s", data);

View file

@ -0,0 +1,3 @@
snprintf(buf, sizeof(buf), "%s%s", prefix, data);

View file

@ -0,0 +1,5 @@
char buf[10];
strncpy(buf, data, sizeof(buf));
buf[sizeof(buf) - 1] = '\0';

View file

@ -0,0 +1,18 @@
int pin_function(void *userdata, int attempt, const char *token_url,
const char *token_label, unsigned flags, char *pin, size_t pin_max)
{
if (flags & GNUTLS_PIN_FINAL_TRY)
printf("This is the final try before locking!\n");
if (flags & GNUTLS_PIN_COUNT_LOW)
printf("Only few tries left before locking!\n");
if (flags & GNUTLS_PIN_WRONG)
printf("Wrong PIN has been provided in the previous attempt\n");
/* userdata is the second value passed to gnutls_pkcs11_set_pin_function()
* in this example we passed the PIN as a null terminated value.
*/
snprintf(pin, pin_max, "%s", (char*)userdata);
return 0;
}

View file

@ -0,0 +1,40 @@
if (module_path) {
ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
if (ret < 0) {
fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret));
exit(1);
}
ret = gnutls_pkcs11_add_provider(module_path, NULL);
if (ret < 0) {
fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret));
exit(1);
}
}
if (key_pass)
gnutls_pkcs11_set_pin_function(pin_function, key_pass);
ret = gnutls_privkey_init(&private_key);
if (ret < 0) {
fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret));
exit(1);
}
ret = gnutls_privkey_import_url(private_key, private_key_name, 0);
if (ret < 0) {
fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret));
exit(1);
}
ret = gnutls_privkey_sign_data(private_key, GNUTLS_DIG_SHA256, 0,
&testdata, &signature);
if (ret < 0) {
fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret));
exit(1);
}
gnutls_privkey_deinit(private_key);
gnutls_free(signature.data);

View file

@ -0,0 +1,23 @@
char *passwdcb(PK11SlotInfo * slot, PRBool retry, void *arg)
{
if (!isatty(STDIN_FILENO) && retry) {
/* we're just reading from a file, and the value is known to be wrong,
* don't keep bounding the token with the wrong password. */
return NULL;
}
if (retry) {
printf("Warning: Wrong PIN has been provided in the previous attempt\n");
if (PK11_IsHW(slot)) {
printf
(" NOTE: multiple pin failures could result in locking your device\n");
}
}
if (pin == NULL)
return pin;
else
return strdup(pin);
}

View file

@ -0,0 +1,56 @@
SECStatus rv;
CERTCertificate *cert = NULL;
SECKEYPrivateKey *pvtkey = NULL;
SECItem signature = { siBuffer, NULL, 0 };
SECOidTag algTag;
int r = 1;
unsigned char buf[] = "test data to sign";
const char *cert_name;
unsigned i;
if (argc < 3) {
fprintf(stderr, "usage: %s [cert name] [PIN]\n\n", argv[0]);
exit(1);
}
cert_name = argv[1];
pin = argv[2];
PK11_SetPasswordFunc(passwdcb);
NSS_InitializePRErrorTable();
rv = NSS_Init(".");
if (rv != SECSuccess) {
fprintf(stderr, "NSS initialization failed (err %d)\n", PR_GetError());
goto cleanup;
}
cert = PK11_FindCertFromNickname(cert_name, NULL);
if (cert == NULL) {
fprintf(stderr, "Couldn't find cert %s in NSS db (err %d: %s)\n",
cert_name, PR_GetError(), PORT_ErrorToString(PR_GetError()));
goto cleanup;
}
fprintf(stderr, "Buffer being signed = \n%s\n", buf);
pvtkey = PK11_FindKeyByAnyCert(cert, NULL);
if (pvtkey == NULL) {
fprintf(stderr, "Couldn't find private key for cert %s (err %d: %s)\n",
cert_name, PR_GetError(), PORT_ErrorToString(PR_GetError()));
goto cleanup;
}
/* get the algtag. Pick the default hash algorithm */
algTag = SEC_GetSignatureAlgorithmOidTag(pvtkey->keyType, SEC_OID_UNKNOWN);
fprintf(stderr, "Signing with alg = %s (%d)\n",
SECOID_FindOIDTagDescription(algTag), algTag);
rv = SEC_SignData(&signature, buf, sizeof(buf)-1, pvtkey, algTag);
if (rv != SECSuccess) {
fprintf(stderr, "sign with Private Key failed (err %d: %s)\n",
PR_GetError(), PORT_ErrorToString(PR_GetError()));
goto cleanup;
}

View file

@ -0,0 +1,64 @@
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
ERR_clear_error();
ENGINE_load_builtin_engines();
e = ENGINE_by_id("pkcs11");
if (!e) {
display_openssl_errors(__LINE__);
exit(1);
}
if (module_path) {
fprintf(stderr, "loading: %s\n", module_path);
if (!ENGINE_ctrl_cmd_string(e, "MODULE_PATH", module_path, 0)) {
display_openssl_errors(__LINE__);
exit(1);
}
}
if (!ENGINE_init(e)) {
display_openssl_errors(__LINE__);
exit(1);
}
if (key_pass && !ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0)) {
display_openssl_errors(__LINE__);
exit(1);
}
private_key = ENGINE_load_private_key(e, private_key_name, NULL, NULL);
if (!private_key) {
fprintf(stderr, "cannot load: %s\n", private_key_name);
display_openssl_errors(__LINE__);
exit(1);
}
display_openssl_errors(__LINE__);
digest_algo = EVP_get_digestbyname("sha256");
EVP_MD_CTX_init(&ctx);
if (EVP_DigestInit(&ctx, digest_algo) <= 0) {
display_openssl_errors(__LINE__);
exit(1);
}
EVP_SignInit(&ctx, digest_algo);
#define TEST_DATA "test data"
if (EVP_SignUpdate(&ctx, TEST_DATA, sizeof(TEST_DATA) - 1) <= 0) {
display_openssl_errors(__LINE__);
exit(1);
}
n = sizeof(buf);
if (EVP_SignFinal(&ctx, buf, &n, private_key) <= 0) {
display_openssl_errors(__LINE__);
exit(1);
}
EVP_PKEY_free(private_key);
ENGINE_finish(e);

View file

@ -0,0 +1,46 @@
// Create the session object.
gnutls_session_t session;
ret = gnutls_init(&session, GNUTLS_CLIENT);
if (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, "error: gnutls_init: %s\n",
gnutls_strerror(ret));
exit(1);
}
// Configure the cipher preferences.
const char *errptr = NULL;
ret = gnutls_priority_set_direct(session, "NORMAL", &errptr);
if (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, "error: gnutls_priority_set_direct: %s\n"
"error: at: \"%s\"\n", gnutls_strerror(ret), errptr);
exit(1);
}
// Install the trusted certificates.
ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);
if (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, "error: gnutls_credentials_set: %s\n",
gnutls_strerror(ret));
exit(1);
}
// Associate the socket with the session object and set the server
// name.
gnutls_transport_set_int(session, sockfd);
ret = gnutls_server_name_set(session, GNUTLS_NAME_DNS,
host, strlen(host));
if (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, "error: gnutls_server_name_set: %s\n",
gnutls_strerror(ret));
exit(1);
}
// Establish the session.
ret = gnutls_handshake(session);
if (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, "error: gnutls_handshake: %s\n",
gnutls_strerror(ret));
exit(1);
}

View file

@ -0,0 +1,21 @@
// Load the trusted CA certificates.
gnutls_certificate_credentials_t cred = NULL;
int ret = gnutls_certificate_allocate_credentials (&cred);
if (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, "error: gnutls_certificate_allocate_credentials: %s\n",
gnutls_strerror(ret));
exit(1);
}
ret = gnutls_certificate_set_x509_system_trust(cred);
if (ret == 0) {
fprintf(stderr, "error: no certificates found in system trust store\n");
exit(1);
}
if (ret < 0) {
fprintf(stderr, "error: gnutls_certificate_set_x509_system_trust: %s\n",
gnutls_strerror(ret));
exit(1);
}

View file

@ -0,0 +1,38 @@
// Obtain the server certificate chain. The server certificate
// itself is stored in the first element of the array.
unsigned certslen = 0;
const gnutls_datum_t *const certs =
gnutls_certificate_get_peers(session, &certslen);
if (certs == NULL || certslen == 0) {
fprintf(stderr, "error: could not obtain peer certificate\n");
exit(1);
}
// Validate the certificate chain.
unsigned status = (unsigned)-1;
ret = gnutls_certificate_verify_peers3(session, host, &status);
if (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, "error: gnutls_certificate_verify_peers3: %s\n",
gnutls_strerror(ret));
exit(1);
}
if (status != 0 && !certificate_validity_override(certs[0])) {
gnutls_datum_t msg;
#if GNUTLS_VERSION_AT_LEAST_3_1_4
int type = gnutls_certificate_type_get (session);
ret = gnutls_certificate_verification_status_print(status, type, &out, 0);
#else
ret = -1;
#endif
if (ret == 0) {
fprintf(stderr, "error: %s\n", msg.data);
gnutls_free(msg.data);
exit(1);
} else {
fprintf(stderr, "error: certificate validation failed with code 0x%x\n",
status);
exit(1);
}
}

View file

@ -0,0 +1,11 @@
// Send close_notify alert.
if (PR_Shutdown(nspr, PR_SHUTDOWN_BOTH) != PR_SUCCESS) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: PR_Read error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
// Closes the underlying POSIX file descriptor, too.
PR_Close(nspr);

View file

@ -0,0 +1,76 @@
// Wrap the POSIX file descriptor. This is an internal NSPR
// function, but it is very unlikely to change.
PRFileDesc* nspr = PR_ImportTCPSocket(sockfd);
sockfd = -1; // Has been taken over by NSPR.
// Add the SSL layer.
{
PRFileDesc *model = PR_NewTCPSocket();
PRFileDesc *newfd = SSL_ImportFD(NULL, model);
if (newfd == NULL) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: NSPR error code %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
model = newfd;
newfd = NULL;
if (SSL_OptionSet(model, SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: set SSL_ENABLE_SSL2 error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
if (SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, PR_FALSE) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: set SSL_V2_COMPATIBLE_HELLO error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
if (SSL_OptionSet(model, SSL_ENABLE_DEFLATE, PR_FALSE) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: set SSL_ENABLE_DEFLATE error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
// Allow overriding invalid certificate.
if (SSL_BadCertHook(model, bad_certificate, (char *)host) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: SSL_BadCertHook error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
newfd = SSL_ImportFD(model, nspr);
if (newfd == NULL) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: SSL_ImportFD error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
nspr = newfd;
PR_Close(model);
}
// Perform the handshake.
if (SSL_ResetHandshake(nspr, PR_FALSE) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: SSL_ResetHandshake error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
if (SSL_SetURL(nspr, host) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: SSL_SetURL error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
if (SSL_ForceHandshake(nspr) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: SSL_ForceHandshake error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}

View file

@ -0,0 +1,22 @@
// Create the socket and connect it at the TCP layer.
SSLSocket socket = (SSLSocket) ctx.getSocketFactory()
.createSocket(host, port);
// Disable the Nagle algorithm.
socket.setTcpNoDelay(true);
// Adjust ciphers and protocols.
socket.setSSLParameters(params);
// Perform the handshake.
socket.startHandshake();
// Validate the host name. The match() method throws
// CertificateException on failure.
X509Certificate peer = (X509Certificate)
socket.getSession().getPeerCertificates()[0];
// This is the only way to perform host name checking on OpenJDK 6.
HostnameChecker.getInstance(HostnameChecker.TYPE_TLS).match(
host, peer);

View file

@ -0,0 +1,22 @@
// Create the context. Specify the SunJSSE provider to avoid
// picking up third-party providers. Try the TLS 1.2 provider
// first, then fall back to TLS 1.0.
SSLContext ctx;
try {
ctx = SSLContext.getInstance("TLSv1.2", "SunJSSE");
} catch (NoSuchAlgorithmException e) {
try {
ctx = SSLContext.getInstance("TLSv1", "SunJSSE");
} catch (NoSuchAlgorithmException e1) {
// The TLS 1.0 provider should always be available.
throw new AssertionError(e1);
} catch (NoSuchProviderException e1) {
throw new AssertionError(e1);
}
} catch (NoSuchProviderException e) {
// The SunJSSE provider should always be available.
throw new AssertionError(e);
}
ctx.init(null, null, null);

View file

@ -0,0 +1,18 @@
SSLContext ctx;
try {
ctx = SSLContext.getInstance("TLSv1.2", "SunJSSE");
} catch (NoSuchAlgorithmException e) {
try {
ctx = SSLContext.getInstance("TLSv1", "SunJSSE");
} catch (NoSuchAlgorithmException e1) {
throw new AssertionError(e1);
} catch (NoSuchProviderException e1) {
throw new AssertionError(e1);
}
} catch (NoSuchProviderException e) {
throw new AssertionError(e);
}
MyTrustManager tm = new MyTrustManager(certHash);
ctx.init(null, new TrustManager[] {tm}, null);

View file

@ -0,0 +1,3 @@
params.setEndpointIdentificationAlgorithm("HTTPS");

View file

@ -0,0 +1,14 @@
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import sun.security.util.HostnameChecker;

View file

@ -0,0 +1,34 @@
public class MyTrustManager implements X509TrustManager {
private final byte[] certHash;
public MyTrustManager(byte[] certHash) throws Exception {
this.certHash = certHash;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throw new UnsupportedOperationException();
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
byte[] digest = getCertificateDigest(chain[0]);
String digestHex = formatHex(digest);
if (Arrays.equals(digest, certHash)) {
System.err.println("info: accepting certificate: " + digestHex);
} else {
throw new CertificateException("certificate rejected: " +
digestHex);
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}

View file

@ -0,0 +1,7 @@
socket.getOutputStream().write("GET / HTTP/1.0\r\n\r\n"
.getBytes(Charset.forName("UTF-8")));
byte[] buffer = new byte[4096];
int count = socket.getInputStream().read(buffer);
System.out.write(buffer, 0, count);

View file

@ -0,0 +1,67 @@
// Configure a client connection context. Send a hendshake for the
// highest supported TLS version, and disable compression.
const SSL_METHOD *const req_method = SSLv23_client_method();
SSL_CTX *const ctx = SSL_CTX_new(req_method);
if (ctx == NULL) {
ERR_print_errors(bio_err);
exit(1);
}
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION);
// Adjust the ciphers list based on a whitelist. First enable all
// ciphers of at least medium strength, to get the list which is
// compiled into OpenSSL.
if (SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM") != 1) {
ERR_print_errors(bio_err);
exit(1);
}
{
// Create a dummy SSL session to obtain the cipher list.
SSL *ssl = SSL_new(ctx);
if (ssl == NULL) {
ERR_print_errors(bio_err);
exit(1);
}
STACK_OF(SSL_CIPHER) *active_ciphers = SSL_get_ciphers(ssl);
if (active_ciphers == NULL) {
ERR_print_errors(bio_err);
exit(1);
}
// Whitelist of candidate ciphers.
static const char *const candidates[] = {
"AES128-GCM-SHA256", "AES128-SHA256", "AES256-SHA256", // strong ciphers
"AES128-SHA", "AES256-SHA", // strong ciphers, also in older versions
"RC4-SHA", "RC4-MD5", // backwards compatibility, supposed to be weak
"DES-CBC3-SHA", "DES-CBC3-MD5", // more backwards compatibility
NULL
};
// Actually selected ciphers.
char ciphers[300];
ciphers[0] = '\0';
for (const char *const *c = candidates; *c; ++c) {
for (int i = 0; i < sk_SSL_CIPHER_num(active_ciphers); ++i) {
if (strcmp(SSL_CIPHER_get_name(sk_SSL_CIPHER_value(active_ciphers, i)),
*c) == 0) {
if (*ciphers) {
strcat(ciphers, ":");
}
strcat(ciphers, *c);
break;
}
}
}
SSL_free(ssl);
// Apply final cipher list.
if (SSL_CTX_set_cipher_list(ctx, ciphers) != 1) {
ERR_print_errors(bio_err);
exit(1);
}
}
// Load the set of trusted root certificates.
if (!SSL_CTX_set_default_verify_paths(ctx)) {
ERR_print_errors(bio_err);
exit(1);
}

View file

@ -0,0 +1,51 @@
// Create the connection object.
SSL *ssl = SSL_new(ctx);
if (ssl == NULL) {
ERR_print_errors(bio_err);
exit(1);
}
SSL_set_fd(ssl, sockfd);
// Enable the ServerNameIndication extension
if (!SSL_set_tlsext_host_name(ssl, host)) {
ERR_print_errors(bio_err);
exit(1);
}
// Perform the TLS handshake with the server.
ret = SSL_connect(ssl);
if (ret != 1) {
// Error status can be 0 or negative.
ssl_print_error_and_exit(ssl, "SSL_connect", ret);
}
// Obtain the server certificate.
X509 *peercert = SSL_get_peer_certificate(ssl);
if (peercert == NULL) {
fprintf(stderr, "peer certificate missing");
exit(1);
}
// Check the certificate verification result. Allow an explicit
// certificate validation override in case verification fails.
int verifystatus = SSL_get_verify_result(ssl);
if (verifystatus != X509_V_OK && !certificate_validity_override(peercert)) {
fprintf(stderr, "SSL_connect: verify result: %s\n",
X509_verify_cert_error_string(verifystatus));
exit(1);
}
// Check if the server certificate matches the host name used to
// establish the connection.
// FIXME: Currently needs OpenSSL 1.1.
if (X509_check_host(peercert, (const unsigned char *)host, strlen(host),
0) != 1
&& !certificate_host_name_override(peercert, host)) {
fprintf(stderr, "SSL certificate does not match host name\n");
exit(1);
}
X509_free(peercert);

View file

@ -0,0 +1,11 @@
const char *const req = "GET / HTTP/1.0\r\n\r\n";
if (SSL_write(ssl, req, strlen(req)) < 0) {
ssl_print_error_and_exit(ssl, "SSL_write", ret);
}
char buf[4096];
ret = SSL_read(ssl, buf, sizeof(buf));
if (ret < 0) {
ssl_print_error_and_exit(ssl, "SSL_read", ret);
}

View file

@ -0,0 +1,9 @@
// The following call prints an error message and calls exit() if
// the OpenSSL configuration file is unreadable.
OPENSSL_config(NULL);
// Provide human-readable error messages.
SSL_load_error_strings();
// Register ciphers.
SSL_library_init();

View file

@ -0,0 +1,10 @@
sock = ssl.wrap_socket(sock,
ciphers="HIGH:-aNULL:-eNULL:-PSK:RC4-SHA:RC4-MD5",
ssl_version=ssl.PROTOCOL_TLSv1,
cert_reqs=ssl.CERT_REQUIRED,
ca_certs='/etc/ssl/certs/ca-bundle.crt')
# getpeercert() triggers the handshake as a side effect.
if not check_host_name(sock.getpeercert(), host):
raise IOError("peer certificate does not match host name")

View file

@ -0,0 +1,25 @@
def check_host_name(peercert, name):
"""Simple certificate/host name checker. Returns True if the
certificate matches, False otherwise. Does not support
wildcards."""
# Check that the peer has supplied a certificate.
# None/{} is not acceptable.
if not peercert:
return False
if peercert.has_key("subjectAltName"):
for typ, val in peercert["subjectAltName"]:
if typ == "DNS" and val == name:
return True
else:
# Only check the subject DN if there is no subject alternative
# name.
cn = None
for attr, val in peercert["subject"]:
# Use most-specific (last) commonName attribute.
if attr == "commonName":
cn = val
if cn is not None:
return cn == name
return False

View file

@ -0,0 +1,3 @@
gnutls_certificate_free_credentials(cred);

View file

@ -0,0 +1,10 @@
// Initiate an orderly connection shutdown.
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
if (ret < 0) {
fprintf(stderr, "error: gnutls_bye: %s\n", gnutls_strerror(ret));
exit(1);
}
// Free the session object.
gnutls_deinit(session);

View file

@ -0,0 +1,5 @@
// This is only necessary if compatibility with GnuTLS prior to
// 3.3.0 is required.
gnutls_global_init();

View file

@ -0,0 +1,14 @@
char buf[4096];
snprintf(buf, sizeof(buf), "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", host);
ret = gnutls_record_send(session, buf, strlen(buf));
if (ret < 0) {
fprintf(stderr, "error: gnutls_record_send: %s\n", gnutls_strerror(ret));
exit(1);
}
ret = gnutls_record_recv(session, buf, sizeof(buf));
if (ret < 0) {
fprintf(stderr, "error: gnutls_record_recv: %s\n", gnutls_strerror(ret));
exit(1);
}

View file

@ -0,0 +1,4 @@
SECMOD_DestroyModule(module);
NSS_ShutdownContext(ctx);

View file

@ -0,0 +1,16 @@
// NSPR include files
#include <prerror.h>
#include <prinit.h>
// NSS include files
#include <nss.h>
#include <pk11pub.h>
#include <secmod.h>
#include <ssl.h>
#include <sslproto.h>
// Private API, no other way to turn a POSIX file descriptor into an
// NSPR handle.
NSPR_API(PRFileDesc*) PR_ImportTCPSocket(int);

View file

@ -0,0 +1,67 @@
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
NSSInitContext *const ctx =
NSS_InitContext("sql:/etc/pki/nssdb", "", "", "", NULL,
NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
if (ctx == NULL) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: NSPR error code %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
// Ciphers to enable.
static const PRUint16 good_ciphers[] = {
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_256_CBC_SHA,
SSL_RSA_WITH_3DES_EDE_CBC_SHA,
SSL_NULL_WITH_NULL_NULL // sentinel
};
// Check if the current policy allows any strong ciphers. If it
// doesn't, set the cipher suite policy. This is not thread-safe
// and has global impact. Consequently, we only do it if absolutely
// necessary.
int found_good_cipher = 0;
for (const PRUint16 *p = good_ciphers; *p != SSL_NULL_WITH_NULL_NULL;
++p) {
PRInt32 policy;
if (SSL_CipherPolicyGet(*p, &policy) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: policy for cipher %u: error %d: %s\n",
(unsigned)*p, err, PR_ErrorToName(err));
exit(1);
}
if (policy == SSL_ALLOWED) {
fprintf(stderr, "info: found cipher %x\n", (unsigned)*p);
found_good_cipher = 1;
break;
}
}
if (!found_good_cipher) {
if (NSS_SetDomesticPolicy() != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: NSS_SetDomesticPolicy: error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
}
// Initialize the trusted certificate store.
char module_name[] = "library=libnssckbi.so name=\"Root Certs\"";
SECMODModule *module = SECMOD_LoadUserModule(module_name, NULL, PR_FALSE);
if (module == NULL || !module->loaded) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: NSPR error code %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}

View file

@ -0,0 +1,18 @@
char buf[4096];
snprintf(buf, sizeof(buf), "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", host);
PRInt32 ret = PR_Write(nspr, buf, strlen(buf));
if (ret < 0) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: PR_Write error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}
ret = PR_Read(nspr, buf, sizeof(buf));
if (ret < 0) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: PR_Read error %d: %s\n",
err, PR_ErrorToName(err));
exit(1);
}

View file

@ -0,0 +1,8 @@
const int val = 1;
int ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
if (ret < 0) {
perror("setsockopt(TCP_NODELAY)");
exit(1);
}

View file

@ -0,0 +1,23 @@
// Prepare TLS parameters. These have to applied to every TLS
// socket before the handshake is triggered.
SSLParameters params = ctx.getDefaultSSLParameters();
// Do not send an SSL-2.0-compatible Client Hello.
ArrayList<String> protocols = new ArrayList<String>(
Arrays.asList(params.getProtocols()));
protocols.remove("SSLv2Hello");
params.setProtocols(protocols.toArray(new String[protocols.size()]));
// Adjust the supported ciphers.
ArrayList<String> ciphers = new ArrayList<String>(
Arrays.asList(params.getCipherSuites()));
ciphers.retainAll(Arrays.asList(
"TLS_RSA_WITH_AES_128_CBC_SHA256",
"TLS_RSA_WITH_AES_256_CBC_SHA256",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_RSA_WITH_RC4_128_SHA1",
"SSL_RSA_WITH_RC4_128_MD5",
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV"));
params.setCipherSuites(ciphers.toArray(new String[ciphers.size()]));

View file

@ -0,0 +1,26 @@
// Send the close_notify alert.
ret = SSL_shutdown(ssl);
switch (ret) {
case 1:
// A close_notify alert has already been received.
break;
case 0:
// Wait for the close_notify alert from the peer.
ret = SSL_shutdown(ssl);
switch (ret) {
case 0:
fprintf(stderr, "info: second SSL_shutdown returned zero\n");
break;
case 1:
break;
default:
ssl_print_error_and_exit(ssl, "SSL_shutdown 2", ret);
}
break;
default:
ssl_print_error_and_exit(ssl, "SSL_shutdown 1", ret);
}
SSL_free(ssl);
close(sockfd);

View file

@ -0,0 +1,3 @@
SSL_CTX_free(ctx);

View file

@ -0,0 +1,27 @@
static void __attribute__((noreturn))
ssl_print_error_and_exit(SSL *ssl, const char *op, int ret)
{
int subcode = SSL_get_error(ssl, ret);
switch (subcode) {
case SSL_ERROR_NONE:
fprintf(stderr, "error: %s: no error to report\n", op);
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_X509_LOOKUP:
case SSL_ERROR_WANT_CONNECT:
case SSL_ERROR_WANT_ACCEPT:
fprintf(stderr, "error: %s: invalid blocking state %d\n", op, subcode);
break;
case SSL_ERROR_SSL:
fprintf(stderr, "error: %s: TLS layer problem\n", op);
case SSL_ERROR_SYSCALL:
fprintf(stderr, "error: %s: system call failed: %s\n", op, strerror(errno));
break;
case SSL_ERROR_ZERO_RETURN:
fprintf(stderr, "error: %s: zero return\n", op);
}
exit(1);
}

View file

@ -0,0 +1,3 @@
sock.close()

View file

@ -0,0 +1,4 @@
sock.write("GET / HTTP/1.1\r\nHost: " + host + "\r\n\r\n")
print sock.read()

View file

@ -0,0 +1,21 @@
func IOError(r io.Reader, buf []byte, processor Processor,
handler ErrorHandler) (message string, err error) {
n, err := r.Read(buf)
// First check for available data.
if n > 0 {
message, err = processor.Process(buf[0:n])
// Regular error handling.
if err != nil {
handler.Handle(err)
return "", err
}
}
// Then handle any error.
if err != nil {
handler.Handle(err)
return "", err
}
return
}

View file

@ -0,0 +1,19 @@
type Processor interface {
Process(buf []byte) (message string, err error)
}
type ErrorHandler interface {
Handle(err error)
}
func RegularError(buf []byte, processor Processor,
handler ErrorHandler) (message string, err error) {
message, err = processor.Process(buf)
if err != nil {
handler.Handle(err)
return "", err
}
return
}

View file

@ -0,0 +1,8 @@
InputStream in = new BufferedInputStream(new FileInputStream(path));
try {
readFile(in);
} finally {
in.close();
}

View file

@ -0,0 +1,32 @@
JNIEXPORT jint JNICALL Java_sum
(JNIEnv *jEnv, jclass clazz, jbyteArray buffer, jint offset, jint length)
{
assert(sizeof(jint) == sizeof(unsigned));
if (offset < 0 || length < 0) {
(*jEnv)->ThrowNew(jEnv, arrayIndexOutOfBoundsExceptionClass,
"negative offset/length");
return 0;
}
unsigned uoffset = offset;
unsigned ulength = length;
// This cannot overflow because of the check above.
unsigned totallength = uoffset + ulength;
unsigned actuallength = (*jEnv)->GetArrayLength(jEnv, buffer);
if (totallength > actuallength) {
(*jEnv)->ThrowNew(jEnv, arrayIndexOutOfBoundsExceptionClass,
"offset + length too large");
return 0;
}
unsigned char *ptr = (*jEnv)->GetPrimitiveArrayCritical(jEnv, buffer, 0);
if (ptr == NULL) {
return 0;
}
unsigned long long sum = 0;
for (unsigned char *p = ptr + uoffset, *end = p + ulength; p != end; ++p) {
sum += *p;
}
(*jEnv)->ReleasePrimitiveArrayCritical(jEnv, buffer, ptr, 0);
return sum;
}

View file

@ -0,0 +1,35 @@
static byte[] readBytes(InputStream in, int length) throws IOException {
final int startSize = 65536;
byte[] b = new byte[Math.min(length, startSize)];
int filled = 0;
while (true) {
int remaining = b.length - filled;
readFully(in, b, filled, remaining);
if (b.length == length) {
break;
}
filled = b.length;
if (length - b.length <= b.length) {
// Allocate final length. Condition avoids overflow.
b = Arrays.copyOf(b, length);
} else {
b = Arrays.copyOf(b, b.length * 2);
}
}
return b;
}
static void readFully(InputStream in,byte[] b, int off, int len)
throws IOException {
int startlen = len;
while (len > 0) {
int count = in.read(b, off, len);
if (count < 0) {
throw new EOFException();
}
off += count;
len -= count;
}
}

View file

@ -0,0 +1,36 @@
interface Callback<T> {
T call(boolean flag);
}
class CallbackInvoker<T> {
private final AccessControlContext context;
Callback<T> callback;
CallbackInvoker(Callback<T> callback) {
context = AccessController.getContext();
this.callback = callback;
}
public T invoke() {
// Obtain increased privileges.
return AccessController.doPrivileged(new PrivilegedAction<T>() {
@Override
public T run() {
// This operation would fail without
// additional privileges.
final boolean flag = Boolean.getBoolean("some.property");
// Restore the original privileges.
return AccessController.doPrivileged(
new PrivilegedAction<T>() {
@Override
public T run() {
return callback.call(flag);
}
}, context);
}
});
}
}

View file

@ -0,0 +1,4 @@
permissions.add(new FilePermission(
System.getProperty("user.dir") + "/-", "read"));

View file

@ -0,0 +1,15 @@
// This is expected to fail.
try {
System.out.println(System.getProperty("user.home"));
} catch (SecurityException e) {
e.printStackTrace(System.err);
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
// This should work.
System.out.println(System.getProperty("user.home"));
return null;
}
});

View file

@ -0,0 +1,24 @@
Permissions permissions = new Permissions();
ProtectionDomain protectionDomain =
new ProtectionDomain(null, permissions);
AccessControlContext context = new AccessControlContext(
new ProtectionDomain[] { protectionDomain });
// This is expected to succeed.
try (FileInputStream in = new FileInputStream(path)) {
System.out.format("FileInputStream: %s%n", in);
}
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
// This code runs with reduced privileges and is
// expected to fail.
try (FileInputStream in = new FileInputStream(path)) {
System.out.format("FileInputStream: %s%n", in);
}
return null;
}
}, context);

View file

@ -0,0 +1,5 @@
try (InputStream in = new BufferedInputStream(new FileInputStream(path))) {
readFile(in);
}

View file

@ -0,0 +1,8 @@
if [[ $value =~ ^-?[0-9]+$ ]] ; then
echo value is an integer
else
echo "value is not an integer" 1>&2
exit 1
fi

View file

@ -0,0 +1,13 @@
XML_Parser parser = XML_ParserCreate("UTF-8");
if (parser == NULL) {
fprintf(stderr, "XML_ParserCreate failed\n");
close(fd);
exit(1);
}
// EntityDeclHandler needs a reference to the parser to stop
// parsing.
XML_SetUserData(parser, parser);
// Disable entity processing, to inhibit entity expansion.
XML_SetEntityDeclHandler(parser, EntityDeclHandler);

View file

@ -0,0 +1,12 @@
// Stop the parser when an entity declaration is encountered.
static void
EntityDeclHandler(void *userData,
const XML_Char *entityName, int is_parameter_entity,
const XML_Char *value, int value_length,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId, const XML_Char *notationName)
{
XML_StopParser((XML_Parser)userData, XML_FALSE);
}

View file

@ -0,0 +1,18 @@
class Errors implements ErrorHandler {
@Override
public void warning(SAXParseException exception) {
exception.printStackTrace();
}
@Override
public void fatalError(SAXParseException exception) {
exception.printStackTrace();
}
@Override
public void error(SAXParseException exception) {
exception.printStackTrace();
}
}

View file

@ -0,0 +1,23 @@
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.w3c.dom.Document;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;

View file

@ -0,0 +1,11 @@
class NoEntityResolver implements EntityResolver {
@Override
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
// Throwing an exception stops validation.
throw new IOException(String.format(
"attempt to resolve \"%s\" \"%s\"", publicId, systemId));
}
}

View file

@ -0,0 +1,13 @@
class NoResourceResolver implements LSResourceResolver {
@Override
public LSInput resolveResource(String type, String namespaceURI,
String publicId, String systemId, String baseURI) {
// Throwing an exception stops validation.
throw new RuntimeException(String.format(
"resolution attempt: type=%s namespace=%s " +
"publicId=%s systemId=%s baseURI=%s",
type, namespaceURI, publicId, systemId, baseURI));
}
}

View file

@ -0,0 +1,15 @@
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// Impose restrictions on the complexity of the DTD.
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
// Turn on validation.
// This step can be omitted if validation is not desired.
factory.setValidating(true);
// Parse the document.
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(new NoEntityResolver());
builder.setErrorHandler(new Errors());
Document document = builder.parse(inputStream);

View file

@ -0,0 +1,19 @@
SchemaFactory factory = SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI);
// This enables restrictions on schema complexity.
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
// The following line prevents resource resolution
// by the schema itself.
factory.setResourceResolver(new NoResourceResolver());
Schema schema = factory.newSchema(schemaFile);
Validator validator = schema.newValidator();
// This prevents external resource resolution.
validator.setResourceResolver(new NoResourceResolver());
validator.validate(new DOMSource(document));

View file

@ -0,0 +1,22 @@
SchemaFactory factory = SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI);
// This enables restrictions on the schema and document
// complexity.
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
// This prevents resource resolution by the schema itself.
// If the schema is trusted and references additional files,
// this line must be omitted, otherwise loading these files
// will fail.
factory.setResourceResolver(new NoResourceResolver());
Schema schema = factory.newSchema(schemaFile);
Validator validator = schema.newValidator();
// This prevents external resource resolution.
validator.setResourceResolver(new NoResourceResolver());
validator.validate(new SAXSource(new InputSource(inputStream)));

View file

@ -0,0 +1,38 @@
class NoEntityHandler : public QXmlDeclHandler {
public:
bool attributeDecl(const QString&, const QString&, const QString&,
const QString&, const QString&);
bool internalEntityDecl(const QString&, const QString&);
bool externalEntityDecl(const QString&, const QString&,
const QString&);
QString errorString() const;
};
bool
NoEntityHandler::attributeDecl
(const QString&, const QString&, const QString&, const QString&,
const QString&)
{
return false;
}
bool
NoEntityHandler::internalEntityDecl(const QString&, const QString&)
{
return false;
}
bool
NoEntityHandler::externalEntityDecl(const QString&, const QString&, const
QString&)
{
return false;
}
QString
NoEntityHandler::errorString() const
{
return "XML declaration not permitted";
}

View file

@ -0,0 +1,21 @@
class NoEntityReader : public QXmlSimpleReader {
NoEntityHandler handler;
public:
NoEntityReader();
void setDeclHandler(QXmlDeclHandler *);
};
NoEntityReader::NoEntityReader()
{
QXmlSimpleReader::setDeclHandler(&handler);
setFeature("http://xml.org/sax/features/namespaces", true);
setFeature("http://xml.org/sax/features/namespace-prefixes", false);
}
void
NoEntityReader::setDeclHandler(QXmlDeclHandler *)
{
// Ignore the handler which was passed in.
}

View file

@ -0,0 +1,12 @@
NoEntityReader reader;
QBuffer buffer(&data);
buffer.open(QIODevice::ReadOnly);
QXmlInputSource source(&buffer);
QDomDocument doc;
QString errorMsg;
int errorLine;
int errorColumn;
bool okay = doc.setContent
(&source, &reader, &errorMsg, &errorLine, &errorColumn);

View file

@ -0,0 +1,151 @@
:experimental:
[[chap-Defensive_Coding-Authentication]]
= Authentication and Authorization
[[sect-Defensive_Coding-Authentication-Server]]
== Authenticating Servers
When connecting to a server, a client has to make sure that it
is actually talking to the server it expects. There are two
different aspects, securing the network path, and making sure
that the expected user runs the process on the target host.
There are several ways to ensure that:
* The server uses a TLS certificate which is valid according
to the web browser public key infrastructure, and the client
verifies the certificate and the host name.
* The server uses a TLS certificate which is expected by the
client (perhaps it is stored in a configuration file read by
the client). In this case, no host name checking is
required.
* On Linux, UNIX domain sockets (of the
`PF_UNIX` protocol family, sometimes called
`PF_LOCAL`) are restricted by file system
permissions. If the server socket path is not
world-writable, the server identity cannot be spoofed by
local users.
* Port numbers less than 1024 (*trusted
ports*) can only be used by
`root`, so if a UDP or TCP server is
running on the local host and it uses a trusted port, its
identity is assured. (Not all operating systems enforce the
trusted ports concept, and the network might not be trusted,
so it is only useful on the local system.)
TLS (<<chap-Defensive_Coding-TLS>>) is the
recommended way for securing connections over untrusted
networks.
If the server port number is 1024 is higher, a local user can
impersonate the process by binding to this socket, perhaps after
crashing the real server by exploiting a denial-of-service
vulnerability.
[[sect-Defensive_Coding-Authentication-Host_based]]
== Host-based Authentication
Host-based authentication uses access control lists (ACLs) to
accept or deny requests from clients. This authentication
method comes in two flavors: IP-based (or, more generally,
address-based) and name-based (with the name coming from DNS or
`/etc/hosts`). IP-based ACLs often use
prefix notation to extend access to entire subnets. Name-based
ACLs sometimes use wildcards for adding groups of hosts (from
entire DNS subtrees). (In the SSH context, host-based
authentication means something completely different and is not
covered in this section.)
Host-based authentication trust the network and may not offer
sufficient granularity, so it has to be considered a weak form
of authentication. On the other hand, IP-based authentication
can be made extremely robust and can be applied very early in
input processing, so it offers an opportunity for significantly
reducing the number of potential attackers for many services.
The names returned by `gethostbyaddr` and
`getnameinfo` functions cannot be trusted.
(DNS PTR records can be set to arbitrary values, not just names
belong to the address owner.) If these names are used for ACL
matching, a forward lookup using
`gethostbyaddr` or
`getaddrinfo` has to be performed. The name
is only valid if the original address is found among the results
of the forward lookup (*double-reverse
lookup*).
An empty ACL should deny all access (deny-by-default). If empty
ACLs permits all access, configuring any access list must switch
to deny-by-default for all unconfigured protocols, in both
name-based and address-based variants.
Similarly, if an address or name is not matched by the list, it
should be denied. However, many implementations behave
differently, so the actual behavior must be documented properly.
IPv6 addresses can embed IPv4 addresses. There is no
universally correct way to deal with this ambiguity. The
behavior of the ACL implementation should be documented.
[[sect-Defensive_Coding-Authentication-UNIX_Domain]]
== UNIX Domain Socket Authentication
UNIX domain sockets (with address family
`AF_UNIX` or `AF_LOCAL`) are
restricted to the local host and offer a special authentication
mechanism: credentials passing.
Nowadays, most systems support the
`SO_PEERCRED` (Linux) or
`LOCAL_PEERCRED` (FreeBSD) socket options, or
the `getpeereid` (other BSDs, OS X).
These interfaces provide direct access to the (effective) user
ID on the other end of a domain socket connect, without
cooperation from the other end.
Historically, credentials passing was implemented using
ancillary data in the `sendmsg` and
`recvmsg` functions. On some systems, only
credentials data that the peer has explicitly sent can be
received, and the kernel checks the data for correctness on the
sending side. This means that both peers need to deal with
ancillary data. Compared to that, the modern interfaces are
easier to use. Both sets of interfaces vary considerably among
UNIX-like systems, unfortunately.
If you want to authenticate based on supplementary groups, you
should obtain the user ID using one of these methods, and look
up the list of supplementary groups using
`getpwuid` (or
`getpwuid_r`) and
`getgrouplist`. Using the PID and
information from `/proc/PID/status` is prone
to race conditions and insecure.
[[sect-Defensive_Coding-Authentication-Netlink]]
== `AF_NETLINK` Authentication of Origin
Netlink messages are used as a high-performance data transfer
mechanism between the kernel and the user space. Traditionally,
they are used to exchange information related to the network
stack, such as routing table entries.
When processing Netlink messages from the kernel, it is
important to check that these messages actually originate from
the kernel, by checking that the port ID (or PID) field
`nl_pid` in the `sockaddr_nl`
structure is `0`. (This structure can be
obtained using `recvfrom` or
`recvmsg`, it is different from the
`nlmsghdr` structure.) The kernel does not
prevent other processes from sending unicast Netlink messages,
but the `nl_pid` field in the sender's socket
address will be non-zero in such cases.
Applications should not use `AF_NETLINK`
sockets as an IPC mechanism among processes, but prefer UNIX
domain sockets for this tasks.

View file

@ -0,0 +1,179 @@
:experimental:
[[chap-Defensive_Coding-HSM]]
= Hardware Security Modules and Smart Cards
Hardware Security Modules (HSMs) are specialized hardware intended
to protect private keys on server systems. They store internally
the private keys (e.g., RSA keys), and provide access to operations
with the keys without exposing the keys. That access, is provided using
a standardized API, which across Fedora is PKCS#11.
Smart cards are small cards with a micro processor, often combined with a
USB reader resembling a USB stick. They are very similar in nature with
HSMs as they can also be used to protect private keys and are almost
universally accessed via the PKCS#11 API. The main distinguishers from HSMs
is their inferior performance and often, the available hardware protection mechanisms.
Typically a smart card or HSM relies on a shared library to provide functionality.
This shared library follows the PKCS#11 API and thus is often referred to as
a PKCS#11 module. In Fedora the `opensc`
shared module (`opensc-pkcs11.so`) can be used for the majority
of smart cards available in the market. By convention these modules are located
at `/usr/lib64/pkcs11`. They can be used directly, or via
a higher level library.
All the major crypto libraries (NSS, GnuTLS and OpenSSL in Fedora) support
hardware security modules and smart cards, by providing wrappers over the
PKCS#11 API. However, the level of support varies, as well as the ease of
use of such modules and its integration to the overall library API.
* The PKCS#11 API does provide an API to access HSMs or smart cards, but
does not provide any method of discovering which HSMs or smart cards are
available in the system. In Fedora and modules are registered via link:++https://p11-glue.freedesktop.org/doc/p11-kit/pkcs11-conf.html++[p11-kit
configuration files], stored at `/etc/pkcs11/modules/`. For applications using
`engine_pkcs11` or GnuTLS the registered modules are
available without further configuration. Other applications will have to load
the `p11-kit-proxy.so` module.
* Most crypto libraries support the link:++https://tools.ietf.org/html/rfc7512++[PKCS#11 URLs scheme]
to identify objects stored in an HSM, however that support is not yet universal.
Some support transparent usage of PKCS#11 objects, e.g., specifying
a PKCS#11 object instead of a file, while others require to use
specialized APIs for such objects.
* Objects stored in an HSM or smart card can be protected with a PIN. As such,
libraries typically require to set a PIN handling function for accessing private keys,
or the PIN can be passed along with a PKCS#11 URL and the pin-value parameter.
* Obtaining a Hardware Security Module, or including it on a continuous integration
testing is not always feasible. For testing purposes smart cards supported by the OpenSC
project can be used, as well as software modules like `softhsm` which
provides a tool to setup a software HSM, and a PKCS#11 library.
* The PKCS#11 API requires applications that use fork to reinitialize the used PKCS#11
modules. This is an uncommon requirement, which has led to several bugs across
applications in Fedora which used PKCS#11 directly. To make things more complicated
software PKCS#11 module like `softhsm` do not require this re-initialization
leading to applications working against software modules but failing with hardware
modules or smart cards. The wrapper PKCS#11 APIs provided by NSS, GnuTLS and
engine_pkcs11 (OpenSSL) handle the reinitialization after fork requirement transparently.
[[sect-Defensive_Coding-HSM-OpenSSL]]
== OpenSSL HSM Support
OpenSSL does not have native support for PKCS#11. It can
provide PKCS#11 support through the OpenSC's project
`pkcs11` engine (formerly known as `engine_pkcs11`).
As such software intended to use HSMs, must utilize that engine.
Engine `pkcs11` supports loading stored objects via PKCS#11 URLs.
If no PKCS#11 module is specified the engine will use the system-wide registered
modules via `p11-kit-proxy.so`.
The following example demonstrates the initialization of the pkcs11 engine
and its usage to sign data.
[[ex-Defensive_Coding-HSM-OpenSSL]]
.Signing data with HSM and OpenSSL
====
[source,c]
----
include::{partialsdir}/snippets/Features-HSM-OpenSSL.adoc[]
----
====
[[sect-Defensive_Coding-HSM-GNUTLS]]
== GnuTLS HSM Support
GnuTLS supports PKCS#11 natively. Most of the API functions
accepting certificate files, can also accept PKCS#11 URLs, thus
requiring minor or no modifications to applications in order
to support HSMs. In most cases applications must be modified
to install a PIN callback function.
The following example demonstrates the initialization of the pkcs11 engine
and its usage to sign data.
[[ex-Defensive_Coding-HSM-GNUTLS]]
.Signing data with HSM and GnuTLS
====
[source,c]
----
include::{partialsdir}/snippets/Features-HSM-GNUTLS.adoc[]
----
====
The PIN callback function can be either set globally as in
the example above or locally by utilizing functions such as `gnutls_privkey_set_pin_function`.
An example PIN callback function is shown below.
[[ex-Defensive_Coding-HSM-GNUTLS-PIN]]
.An example PIN callback with GNUTLS
====
[source,c]
----
include::{partialsdir}/snippets/Features-HSM-GNUTLS-PIN.adoc[]
----
====
[[sect-Defensive_Coding-HSM-NSS]]
== NSS HSM Support
NSS supports PKCS#11 natively. In fact all NSS crypto operations,
including built-in operations, go through PKCS #11 modules. NSS provides
its own software PKCS #11 module called softoken. NSS automatically
loads any PKCS #11 module specified in its module database, which can
be manipulated with the modutil command. NSS uses the PKCS #11 module
that contains the requested keys to do the crypto operations. As long as
the application opens an NSS database and properly sets a pin callback. If
it runs with native NSS, it should be able to use HSMs that provide PKCS #11
modules. Modules can also be loaded programatically, though this is less common.
The following example demonstrates a typical NSS application for signing.
[[ex-Defensive_Coding-HSM-NSS]]
.Signing data with HSM and NSS
====
[source,c]
----
include::{partialsdir}/snippets/Features-HSM-NSS.adoc[]
----
====
To use the example above with an HSM or smart card you will need to do the following.
[source,bash]
----
# add your HSM or token library to an NSS database (in the sample code the database is
# located in the current directory'.')
$ modutil -add "My HSM" -libfile ${path_to_pkcs11_file} -dbdir .
# Find the token name on your HSM
$ modutil -list -dbdir .
# find the cert on your token
$ certutil -L -h ${token_name} -d .
# pass the cert to your signing program
$ NSS_Sign_Example "${token_name}:${cert_name}"
----
[[ex-Defensive_Coding-HSM-NSS-PIN]]
.An example PIN callback with NSS
====
[source,c]
----
include::{partialsdir}/snippets/Features-HSM-NSS-PIN.adoc[]
----
====

View file

@ -0,0 +1,944 @@
:experimental:
[[chap-Defensive_Coding-TLS]]
= Transport Layer Security (TLS)
include::{partialsdir}/entities.adoc[]
Transport Layer Security (TLS, formerly Secure Sockets
Layer/SSL) is the recommended way to to protect integrity and
confidentiality while data is transferred over an untrusted
network connection, and to identify the endpoint. At this
chapter we describe the available libraries in Fedora as well
as known pitfalls, and safe ways to write applications with them.
When using any library, in addition to this guide, it is recommended to consult the
library' documentation.
* link:++https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS++[NSS documentation]
* link:++http://www.gnutls.org/manual/++[GnuTLS documentation]
* link:++https://www.openssl.org/docs/++[OpenSSL documentation]
* link:++https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html++[OpenJDK documentation]
[[sect-Defensive_Coding-TLS-Pitfalls]]
== Common Pitfalls
TLS implementations are difficult to use, and most of them lack
a clean API design. The following sections contain
implementation-specific advice, and some generic pitfalls are
mentioned below.
* Most TLS implementations have questionable default TLS
cipher suites. Most of them enable anonymous Diffie-Hellman
key exchange (but we generally want servers to authenticate
themselves). Many do not disable ciphers which are subject
to brute-force attacks because of restricted key lengths.
Some even disable all variants of AES in the default
configuration.
+
When overriding the cipher suite defaults, it is recommended
to disable all cipher suites which are not present on a
whitelist, instead of simply enabling a list of cipher
suites. This way, if an algorithm is disabled by default in
the TLS implementation in a future security update, the
application will not re-enable it.
* The name which is used in certificate validation must match
the name provided by the user or configuration file. No host
name canonicalization or IP address lookup must be performed.
* The TLS handshake has very poor performance if the TCP Nagle
algorithm is active. You should switch on the
`TCP_NODELAY` socket option (at least for the
duration of the handshake), or use the Linux-specific
`TCP_CORK` option.
+
[[ex-Defensive_Coding-TLS-Nagle]]
.Deactivating the TCP Nagle algorithm
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-Nagle.adoc[]
----
====
* Implementing proper session resumption decreases handshake
overhead considerably. This is important if the upper-layer
protocol uses short-lived connections (like most application
of HTTPS).
* Both client and server should work towards an orderly
connection shutdown, that is send
`close_notify` alerts and respond to them.
This is especially important if the upper-layer protocol
does not provide means to detect connection truncation (like
some uses of HTTP).
* When implementing a server using event-driven programming,
it is important to handle the TLS handshake properly because
it includes multiple network round-trips which can block
when an ordinary TCP `accept` would not.
Otherwise, a client which fails to complete the TLS
handshake for some reason will prevent the server from
handling input from other clients.
* Unlike regular file descriptors, TLS connections cannot be
passed between processes. Some TLS implementations add
additional restrictions, and TLS connections generally
cannot be used across `fork` function
calls (see <<sect-Defensive_Coding-Tasks-Processes-Fork-Parallel>>).
[[sect-Defensive_Coding-TLS-OpenSSL]]
=== OpenSSL Pitfalls
Some OpenSSL function use *tri-state return
values*. Correct error checking is extremely
important. Several functions return `int`
values with the following meaning:
* The value `1` indicates success (for
example, a successful signature verification).
* The value `0` indicates semantic
failure (for example, a signature verification which was
unsuccessful because the signing certificate was
self-signed).
* The value `-1` indicates a low-level
error in the system, such as failure to allocate memory
using `malloc`.
Treating such tri-state return values as booleans can lead
to security vulnerabilities. Note that some OpenSSL
functions return boolean results or yet another set of
status indicators. Each function needs to be checked
individually.
Recovering precise error information is difficult.
<<ex-Defensive_Coding-TLS-OpenSSL-Errors>>
shows how to obtain a more precise error code after a function
call on an `SSL` object has failed. However,
there are still cases where no detailed error information is
available (e.g., if `SSL_shutdown` fails
due to a connection teardown by the other end).
[[ex-Defensive_Coding-TLS-OpenSSL-Errors]]
.Obtaining OpenSSL error codes
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-OpenSSL-Errors.adoc[]
----
====
The `OPENSSL_config` function is
documented to never fail. In reality, it can terminate the
entire process if there is a failure accessing the
configuration file. An error message is written to standard
error, but which might not be visible if the function is
called from a daemon process.
OpenSSL contains two separate ASN.1 DER decoders. One set
of decoders operate on BIO handles (the input/output stream
abstraction provided by OpenSSL); their decoder function
names start with `d2i_` and end in
`_fp` or `_bio` (e.g.,
`d2i_X509_fp` or
`d2i_X509_bio`). These decoders must not
be used for parsing data from untrusted sources; instead,
the variants without the `_fp` and
`_bio` (e.g.,
`d2i_X509`) shall be used. The BIO
variants have received considerably less testing and are not
very robust.
For the same reason, the OpenSSL command line tools (such as
[command]`openssl x509`) are generally generally less
robust than the actual library code. They use the BIO
functions internally, and not the more robust variants.
The command line tools do not always indicate failure in the
exit status of the [application]*openssl* process.
For instance, a verification failure in [command]`openssl
verify` result in an exit status of zero.
OpenSSL command-line commands, such as [command]`openssl
genrsa`, do not ensure that physical entropy is used
for key generation—they obtain entropy from
`/dev/urandom` and other sources, but not
from `/dev/random`. This can result in
weak keys if the system lacks a proper entropy source (e.g., a
virtual machine with solid state storage). Depending on local
policies, keys generated by these OpenSSL tools should not be
used in high-value, critical functions.
The OpenSSL server and client applications ([command]`openssl
s_client` and [command]`openssl s_server`)
are debugging tools and should *never* be
used as generic clients. For instance, the
[application]*s_client* tool reacts in a
surprising way to lines starting with `R` and
`Q`.
OpenSSL allows application code to access private key
material over documented interfaces. This can significantly
increase the part of the code base which has to undergo
security certification.
[[sect-Defensive_Coding-TLS-Pitfalls-GnuTLS]]
=== GnuTLS Pitfalls
Older versions of GnuTLS had several peculiarities described
in previous versions of this guide; as of GnuTLS 3.3.10, these
issues are no longer applicable.
[[sect-Defensive_Coding-TLS-Pitfalls-OpenJDK]]
=== OpenJDK Pitfalls
The Java cryptographic framework is highly modular. As a
result, when you request an object implementing some
cryptographic functionality, you cannot be completely sure
that you end up with the well-tested, reviewed implementation
in OpenJDK.
OpenJDK (in the source code as published by Oracle) and other
implementations of the Java platform require that the system
administrator has installed so-called *unlimited
strength jurisdiction policy files*. Without this
step, it is not possible to use the secure algorithms which
offer sufficient cryptographic strength. Most downstream
redistributors of OpenJDK remove this requirement.
Some versions of OpenJDK use `/dev/random`
as the randomness source for nonces and other random data
which is needed for TLS operation, but does not actually
require physical randomness. As a result, TLS applications
can block, waiting for more bits to become available in
`/dev/random`.
[[sect-Defensive_Coding-TLS-Pitfalls-NSS]]
=== NSS Pitfalls
NSS was not designed to be used by other libraries which can
be linked into applications without modifying them. There is
a lot of global state. There does not seem to be a way to
perform required NSS initialization without race conditions.
If the NSPR descriptor is in an unexpected state, the
`SSL_ForceHandshake` function can succeed,
but no TLS handshake takes place, the peer is not
authenticated, and subsequent data is exchanged in the clear.
NSS disables itself if it detects that the process underwent a
`fork` after the library has been
initialized. This behavior is required by the PKCS#11 API
specification.
[[sect-Defensive_Coding-TLS-Client]]
== TLS Clients
Secure use of TLS in a client generally involves all of the
following steps. (Individual instructions for specific TLS
implementations follow in the next sections.)
* The client must configure the TLS library to use a set of
trusted root certificates. These certificates are provided
by the system in various formats and files. These are documented in `update-ca-trust`
man page in Fedora. Portable applications should not hard-code
any paths; they should rely on APIs which set the default
for the system trust store.
* The client selects sufficiently strong cryptographic
primitives and disables insecure ones (such as no-op
encryption). Compression support and SSL version 3 or lower must be
disabled (including the SSLv2-compatible handshake).
* The client initiates the TLS connection. The Server Name
Indication extension should be used if supported by the
TLS implementation. Before switching to the encrypted
connection state, the contents of all input and output
buffers must be discarded.
* The client needs to validate the peer certificate provided
by the server, that is, the client must check that there
is a cryptographically protected chain from a trusted root
certificate to the peer certificate. (Depending on the
TLS implementation, a TLS handshake can succeed even if
the certificate cannot be validated.)
* The client must check that the configured or user-provided
server name matches the peer certificate provided by the
server.
It is safe to provide users detailed diagnostics on
certificate validation failures. Other causes of handshake
failures and, generally speaking, any details on other errors
reported by the TLS implementation (particularly exception
tracebacks), must not be divulged in ways that make them
accessible to potential attackers. Otherwise, it is possible
to create decryption oracles.
[IMPORTANT]
====
Depending on the application, revocation checking (against
certificate revocations lists or via OCSP) and session
resumption are important aspects of production-quality
client. These aspects are not yet covered.
====
=== Implementation TLS Clients With OpenSSL
In the following code, the error handling is only exploratory.
Proper error handling is required for production use,
especially in libraries.
The OpenSSL library needs explicit initialization (see <<ex-Defensive_Coding-TLS-OpenSSL-Init>>).
[[ex-Defensive_Coding-TLS-OpenSSL-Init]]
.OpenSSL library initialization
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-Client-OpenSSL-Init.adoc[]
----
====
After that, a context object has to be created, which acts as
a factory for connection objects (<<ex-Defensive_Coding-TLS-Client-OpenSSL-CTX>>). We
use an explicit cipher list so that we do not pick up any
strange ciphers when OpenSSL is upgraded. The actual version
requested in the client hello depends on additional
restrictions in the OpenSSL library. If possible, you should
follow the example code and use the default list of trusted
root certificate authorities provided by the system because
you would have to maintain your own set otherwise, which can
be cumbersome.
[[ex-Defensive_Coding-TLS-Client-OpenSSL-CTX]]
.OpenSSL client context creation
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-Client-OpenSSL-CTX.adoc[]
----
====
A single context object can be used to create multiple
connection objects. It is safe to use the same
`SSL_CTX` object for creating connections
concurrently from multiple threads, provided that the
`SSL_CTX` object is not modified (e.g.,
callbacks must not be changed).
After creating the TCP socket and disabling the Nagle
algorithm (per <<ex-Defensive_Coding-TLS-Nagle>>), the actual
connection object needs to be created, as show in <<ex-Defensive_Coding-TLS-Client-OpenSSL-CTX>>. If
the handshake started by `SSL_connect`
fails, the `ssl_print_error_and_exit`
function from <<ex-Defensive_Coding-TLS-OpenSSL-Errors>> is called.
The `certificate_validity_override`
function provides an opportunity to override the validity of
the certificate in case the OpenSSL check fails. If such
functionality is not required, the call can be removed,
otherwise, the application developer has to implement it.
The host name passed to the functions
`SSL_set_tlsext_host_name` and
`X509_check_host` must be the name that was
passed to `getaddrinfo` or a similar name
resolution function. No host name canonicalization must be
performed. The `X509_check_host` function
used in the final step for host name matching is currently
only implemented in OpenSSL 1.1, which is not released yet.
In case host name matching fails, the function
`certificate_host_name_override` is called.
This function should check user-specific certificate store, to
allow a connection even if the host name does not match the
certificate. This function has to be provided by the
application developer. Note that the override must be keyed
by both the certificate *and* the host
name.
[[ex-Defensive_Coding-TLS-Client-OpenSSL-Connect]]
.Creating a client connection using OpenSSL
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-Client-OpenSSL-Connect.adoc[]
----
====
The connection object can be used for sending and receiving
data, as in <<ex-Defensive_Coding-TLS-OpenSSL-Connection-Use>>.
It is also possible to create a `BIO` object
and use the `SSL` object as the underlying
transport, using `BIO_set_ssl`.
[[ex-Defensive_Coding-TLS-OpenSSL-Connection-Use]]
.Using an OpenSSL connection to send and receive data
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-Client-OpenSSL-Connection-Use.adoc[]
----
====
When it is time to close the connection, the
`SSL_shutdown` function needs to be called
twice for an orderly, synchronous connection termination
(<<ex-Defensive_Coding-TLS-OpenSSL-Connection-Close>>).
This exchanges `close_notify` alerts with the
server. The additional logic is required to deal with an
unexpected `close_notify` from the server.
Note that is necessary to explicitly close the underlying
socket after the connection object has been freed.
[[ex-Defensive_Coding-TLS-OpenSSL-Connection-Close]]
.Closing an OpenSSL connection in an orderly fashion
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-OpenSSL-Connection-Close.adoc[]
----
====
<<ex-Defensive_Coding-TLS-OpenSSL-Context-Close>> shows how
to deallocate the context object when it is no longer needed
because no further TLS connections will be established.
[[ex-Defensive_Coding-TLS-OpenSSL-Context-Close]]
.Closing an OpenSSL connection in an orderly fashion
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-OpenSSL-Context-Close.adoc[]
----
====
[[sect-Defensive_Coding-TLS-Client-GnuTLS]]
=== Implementation TLS Clients With GnuTLS
This section describes how to implement a TLS client with full
certificate validation (but without certificate revocation
checking). Note that the error handling in is only
exploratory and needs to be replaced before production use.
Before setting up TLS connections, a credentials objects has
to be allocated and initialized with the set of trusted root
CAs (<<ex-Defensive_Coding-TLS-Client-GNUTLS-Credentials>>).
[[ex-Defensive_Coding-TLS-Client-GNUTLS-Credentials]]
.Initializing a GnuTLS credentials structure
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-Client-GNUTLS-Credentials.adoc[]
----
====
After the last TLS connection has been closed, this credentials
object should be freed:
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-GNUTLS-Credentials-Close.adoc[]
----
During its lifetime, the credentials object can be used to
initialize TLS session objects from multiple threads, provided
that it is not changed.
Once the TCP connection has been established, the Nagle
algorithm should be disabled (see <<ex-Defensive_Coding-TLS-Nagle>>). After that, the
socket can be associated with a new GnuTLS session object.
The previously allocated credentials object provides the set
of root CAs. Then the TLS handshake must be initiated.
This is shown in <<ex-Defensive_Coding-TLS-Client-GNUTLS-Connect>>.
[[ex-Defensive_Coding-TLS-Client-GNUTLS-Connect]]
.Establishing a TLS client connection using GnuTLS
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-Client-GNUTLS-Connect.adoc[]
----
====
After the handshake has been completed, the server certificate
needs to be verified against the server's hostname (<<ex-Defensive_Coding-TLS-Client-GNUTLS-Verify>>). In
the example, the user-defined
`certificate_validity_override` function is
called if the verification fails, so that a separate,
user-specific trust store can be checked. This function call
can be omitted if the functionality is not needed.
[[ex-Defensive_Coding-TLS-Client-GNUTLS-Verify]]
.Verifying a server certificate using GnuTLS
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-Client-GNUTLS-Verify.adoc[]
----
====
An established TLS session can be used for sending and
receiving data, as in <<ex-Defensive_Coding-TLS-GNUTLS-Use>>.
[[ex-Defensive_Coding-TLS-GNUTLS-Use]]
.Using a GnuTLS session
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-GNUTLS-Use.adoc[]
----
====
In order to shut down a connection in an orderly manner, you
should call the `gnutls_bye` function.
Finally, the session object can be deallocated using
`gnutls_deinit` (see <<ex-Defensive_Coding-TLS-GNUTLS-Disconnect>>).
[[ex-Defensive_Coding-TLS-GNUTLS-Disconnect]]
.Closing a GnuTLS session in an orderly fashion
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-GNUTLS-Disconnect.adoc[]
----
====
[[sect-Defensive_Coding-TLS-Client-OpenJDK]]
=== Implementing TLS Clients With OpenJDK
The examples below use the following cryptographic-related
classes:
[source,java]
----
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Import.adoc[]
----
If compatibility with OpenJDK 6 is required, it is necessary
to use the internal class
`sun.security.util.HostnameChecker`. (The
public OpenJDK API does not provide any support for dissecting
the subject distinguished name of an X.509 certificate, so a
custom-written DER parser is needed—or we have to use an
internal class, which we do below.) In OpenJDK 7, the
`setEndpointIdentificationAlgorithm` method
was added to the
`javax.net.ssl.SSLParameters` class,
providing an official way to implement host name checking.
TLS connections are established using an
`SSLContext` instance. With a properly
configured OpenJDK installation, the
`SunJSSE` provider uses the system-wide set
of trusted root certificate authorities, so no further
configuration is necessary. For backwards compatibility with
OpenJDK{nbsp}6, the `TLSv1` provider has to
be supported as a fall-back option. This is shown in <<ex-Defensive_Coding-TLS-Client-OpenJDK-Context>>.
[[ex-Defensive_Coding-TLS-Client-OpenJDK-Context]]
.Setting up an `SSLContext` for OpenJDK TLS clients
====
[source,java]
----
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Context.adoc[]
----
====
In addition to the context, a TLS parameter object will be
needed which adjusts the cipher suites and protocols (<<ex-Defensive_Coding-TLS-OpenJDK-Parameters>>). Like
the context, these parameters can be reused for multiple TLS
connections.
[[ex-Defensive_Coding-TLS-OpenJDK-Parameters]]
.Setting up `SSLParameters` for TLS use with OpenJDK
====
[source,java]
----
include::{partialsdir}/snippets/Features-TLS-OpenJDK-Parameters.adoc[]
----
====
As initialized above, the parameter object does not yet
require host name checking. This has to be enabled
separately, and this is only supported by OpenJDK 7 and later:
[source,java]
----
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Hostname.adoc[]
----
All application protocols can use the
`"HTTPS"` algorithm. (The algorithms have
minor differences with regard to wildcard handling, which
should not matter in practice.)
<<ex-Defensive_Coding-TLS-Client-OpenJDK-Connect>>
shows how to establish the connection. Before the handshake
is initialized, the protocol and cipher configuration has to
be performed, by applying the parameter object
`params`. (After this point, changes to
`params` will not affect this TLS socket.)
As mentioned initially, host name checking requires using an
internal API on OpenJDK 6.
[[ex-Defensive_Coding-TLS-Client-OpenJDK-Connect]]
.Establishing a TLS connection with OpenJDK
====
[source,java]
----
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Connect.adoc[]
----
====
Starting with OpenJDK 7, the last lines can be omitted,
provided that host name verification has been enabled by
calling the
`setEndpointIdentificationAlgorithm` method
on the `params` object (before it was applied
to the socket).
The TLS socket can be used as a regular socket, as shown in
<<ex-Defensive_Coding-TLS-Client-OpenJDK-Use>>.
[[ex-Defensive_Coding-TLS-Client-OpenJDK-Use]]
.Using a TLS client socket in OpenJDK
====
[source,java]
----
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Use.adoc[]
----
====
==== Overriding server certificate validation with OpenJDK 6
Overriding certificate validation requires a custom trust
manager. With OpenJDK 6, the trust manager lacks
information about the TLS session, and to which server the
connection is made. Certificate overrides have to be tied
to specific servers (host names). Consequently, different
`TrustManager` and
`SSLContext` objects have to be used for
different servers.
In the trust manager shown in <<ex-Defensive_Coding-TLS-Client-MyTrustManager>>,
the server certificate is identified by its SHA-256 hash.
[[ex-Defensive_Coding-TLS-Client-MyTrustManager]]
.A customer trust manager for OpenJDK TLS clients
====
[source,java]
----
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-MyTrustManager.adoc[]
----
====
This trust manager has to be passed to the
`init` method of the
`SSLContext` object, as show in <<ex-Defensive_Coding-TLS-Client-Context_For_Cert>>.
[[ex-Defensive_Coding-TLS-Client-Context_For_Cert]]
.Using a custom TLS trust manager with OpenJDK
====
[source,java]
----
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Context_For_Cert.adoc[]
----
====
When certificate overrides are in place, host name
verification should not be performed because there is no
security requirement that the host name in the certificate
matches the host name used to establish the connection (and
it often will not). However, without host name
verification, it is not possible to perform transparent
fallback to certification validation using the system
certificate store.
The approach described above works with OpenJDK 6 and later
versions. Starting with OpenJDK 7, it is possible to use a
custom subclass of the
`javax.net.ssl.X509ExtendedTrustManager`
class. The OpenJDK TLS implementation will call the new
methods, passing along TLS session information. This can be
used to implement certificate overrides as a fallback (if
certificate or host name verification fails), and a trust
manager object can be used for multiple servers because the
server address is available to the trust manager.
[[sect-Defensive_Coding-TLS-Client-NSS]]
=== Implementing TLS Clients With NSS
The following code shows how to implement a simple TLS client
using NSS. These instructions apply to NSS version 3.14 and
later. Versions before 3.14 need different initialization
code.
Keep in mind that the error handling needs to be improved
before the code can be used in production.
Using NSS needs several header files, as shown in
<<ex-Defensive_Coding-TLS-NSS-Includes>>.
[[ex-Defensive_Coding-TLS-NSS-Includes]]
.Include files for NSS
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-NSS-Includes.adoc[]
----
====
Initializing the NSS library is shown in <<ex-Defensive_Coding-TLS-NSS-Init>>. This
initialization procedure overrides global state. We only call
`NSS_SetDomesticPolicy` if there are no
strong ciphers available, assuming that it has already been
called otherwise. This avoids overriding the process-wide
cipher suite policy unnecessarily.
The simplest way to configured the trusted root certificates
involves loading the `libnssckbi.so` NSS
module with a call to the
`SECMOD_LoadUserModule` function. The root
certificates are compiled into this module. (The PEM module
for NSS, `libnsspem.so`, offers a way to
load trusted CA certificates from a file.)
[[ex-Defensive_Coding-TLS-NSS-Init]]
.Initializing the NSS library
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-NSS-Init.adoc[]
----
====
Some of the effects of the initialization can be reverted with
the following function calls:
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-NSS-Close.adoc[]
----
After NSS has been initialized, the TLS connection can be
created (<<ex-Defensive_Coding-TLS-Client-NSS-Connect>>). The
internal `PR_ImportTCPSocket` function is
used to turn the POSIX file descriptor
`sockfd` into an NSPR file descriptor. (This
function is de-facto part of the NSS public ABI, so it will
not go away.) Creating the TLS-capable file descriptor
requires a *model* descriptor, which is
configured with the desired set of protocols. The model
descriptor is not needed anymore after TLS support has been
activated for the existing connection descriptor.
The call to `SSL_BadCertHook` can be
omitted if no mechanism to override certificate verification
is needed. The `bad_certificate` function
must check both the host name specified for the connection and
the certificate before granting the override.
Triggering the actual handshake requires three function calls,
`SSL_ResetHandshake`,
`SSL_SetURL`, and
`SSL_ForceHandshake`. (If
`SSL_ResetHandshake` is omitted,
`SSL_ForceHandshake` will succeed, but the
data will not be encrypted.) During the handshake, the
certificate is verified and matched against the host name.
[[ex-Defensive_Coding-TLS-Client-NSS-Connect]]
.Creating a TLS connection with NSS
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-Client-NSS-Connect.adoc[]
----
====
After the connection has been established, <<ex-Defensive_Coding-TLS-NSS-Use>> shows how to use
the NSPR descriptor to communicate with the server.
[[ex-Defensive_Coding-TLS-NSS-Use]]
.Using NSS for sending and receiving data
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-NSS-Use.adoc[]
----
====
<<ex-Defensive_Coding-TLS-Client-NSS-Close>>
shows how to close the connection.
[[ex-Defensive_Coding-TLS-Client-NSS-Close]]
.Closing NSS client connections
====
[source,c]
----
include::{partialsdir}/snippets/Features-TLS-Client-NSS-Close.adoc[]
----
====
[[sect-Defensive_Coding-TLS-Client-Python]]
=== Implementing TLS Clients With Python
The Python distribution provides a TLS implementation in the
`ssl` module (actually a wrapper around
OpenSSL). The exported interface is somewhat restricted, so
that the client code shown below does not fully implement the
recommendations in <<sect-Defensive_Coding-TLS-OpenSSL>>.
[IMPORTANT]
====
Currently, most Python function which accept
`https://` URLs or otherwise implement
HTTPS support do not perform certificate validation at all.
(For example, this is true for the `httplib`
and `xmlrpclib` modules.) If you use
HTTPS, you should not use the built-in HTTP clients. The
`Curl` class in the `curl`
module, as provided by the `python-pycurl`
package implements proper certificate validation.
====
The `ssl` module currently does not perform
host name checking on the server certificate. <<ex-Defensive_Coding-TLS-Client-Python-check_host_name>>
shows how to implement certificate matching, using the parsed
certificate returned by `getpeercert`.
[[ex-Defensive_Coding-TLS-Client-Python-check_host_name]]
.Implementing TLS host name checking Python (without wildcard support)
====
[source,python]
----
include::{partialsdir}/snippets/Features-TLS-Client-Python-check_host_name.adoc[]
----
====
To turn a regular, connected TCP socket into a TLS-enabled
socket, use the `ssl.wrap_socket` function.
The function call in <<ex-Defensive_Coding-TLS-Client-Python-Connect>>
provides additional arguments to override questionable
defaults in OpenSSL and in the Python module.
* `ciphers="HIGH:-aNULL:-eNULL:-PSK:RC4-SHA:RC4-MD5"`
selects relatively strong cipher suites with
certificate-based authentication. (The call to
`check_host_name` function provides
additional protection against anonymous cipher suites.)
* `ssl_version=ssl.PROTOCOL_TLSv1` disables
SSL 2.0 support. By default, the `ssl`
module sends an SSL 2.0 client hello, which is rejected by
some servers. Ideally, we would request OpenSSL to
negotiated the most recent TLS version supported by the
server and the client, but the Python module does not
allow this.
* `cert_reqs=ssl.CERT_REQUIRED` turns on
certificate validation.
* `ca_certs='/etc/ssl/certs/ca-bundle.crt'`
initializes the certificate store with a set of trusted
root CAs. Unfortunately, it is necessary to hard-code
this path into applications because the default path in
OpenSSL is not available through the Python
`ssl` module.
The `ssl` module (and OpenSSL) perform
certificate validation, but the certificate must be compared
manually against the host name, by calling the
`check_host_name` defined above.
[[ex-Defensive_Coding-TLS-Client-Python-Connect]]
.Establishing a TLS client connection with Python
====
[source,python]
----
include::{partialsdir}/snippets/Features-TLS-Client-Python-Connect.adoc[]
----
====
After the connection has been established, the TLS socket can
be used like a regular socket:
[source,python]
----
include::{partialsdir}/snippets/Features-TLS-Python-Use.adoc[]
----
Closing the TLS socket is straightforward as well:
[source,python]
----
include::{partialsdir}/snippets/Features-TLS-Python-Close.adoc[]
----

View file

@ -0,0 +1,18 @@
:experimental:
include::{partialsdir}/entities.adoc[]
A Guide to Improving Software Security
[abstract]
--
This document provides guidelines for improving software
security through secure coding. It covers common
programming languages and libraries, and focuses on
concrete recommendations.
--
image::title_logo.svg[]
include::{partialsdir}/Legal_Notice.adoc[]
include::{partialsdir}/Author_Group.adoc[]

View file

@ -0,0 +1,13 @@
<abstract>
<para>
This document provides guidelines for improving software
security through secure coding. It covers common
programming languages and libraries, and focuses on
concrete recommendations.
</para>
</abstract>
<edition>1</edition>
<productname>Fedora Security Team</productname>
<productnumber></productnumber>
<pubsnumber>1</pubsnumber>
<subtitle>A Guide to Improving Software Security</subtitle>

View file

@ -0,0 +1,166 @@
:experimental:
[[sect-Defensive_Coding-C-Allocators]]
== Memory Allocators
=== `malloc` and Related Functions
The C library interfaces for memory allocation are provided by
`malloc`, `free` and
`realloc`, and the
`calloc` function. In addition to these
generic functions, there are derived functions such as
`strdup` which perform allocation using
`malloc` internally, but do not return
untyped heap memory (which could be used for any object).
The C compiler knows about these functions and can use their
expected behavior for optimizations. For instance, the compiler
assumes that an existing pointer (or a pointer derived from an
existing pointer by arithmetic) will not point into the memory
area returned by `malloc`.
If the allocation fails, `realloc` does not
free the old pointer. Therefore, the idiom `ptr =
realloc(ptr, size);` is wrong because the memory
pointed to by `ptr` leaks in case of an error.
[[sect-Defensive_Coding-C-Use-After-Free]]
==== Use-after-free errors
After `free`, the pointer is invalid.
Further pointer dereferences are not allowed (and are usually
detected by [application]*valgrind*). Less obvious
is that any *use* of the old pointer value is
not allowed, either. In particular, comparisons with any other
pointer (or the null pointer) are undefined according to the C
standard.
The same rules apply to `realloc` if the
memory area cannot be enlarged in-place. For instance, the
compiler may assume that a comparison between the old and new
pointer will always return false, so it is impossible to detect
movement this way.
==== Handling Memory Allocation Errors
Recovering from out-of-memory errors is often difficult or even
impossible. In these cases, `malloc` and
other allocation functions return a null pointer. Dereferencing
this pointer lead to a crash. Such dereferences can even be
exploitable for code execution if the dereference is combined
with an array subscript.
In general, if you cannot check all allocation calls and
handle failure, you should abort the program on allocation
failure, and not rely on the null pointer dereference to
terminate the process. See
<<sect-Defensive_Coding-Tasks-Serialization-Decoders>>
for related memory allocation concerns.
[[sect-Defensive_Coding-C-Allocators-alloca]]
=== `alloca` and Other Forms of Stack-based Allocation
Allocation on the stack is risky because stack overflow checking
is implicit. There is a guard page at the end of the memory
area reserved for the stack. If the program attempts to read
from or write to this guard page, a `SIGSEGV`
signal is generated and the program typically terminates.
This is sufficient for detecting typical stack overflow
situations such as unbounded recursion, but it fails when the
stack grows in increments larger than the size of the guard
page. In this case, it is possible that the stack pointer ends
up pointing into a memory area which has been allocated for a
different purposes. Such misbehavior can be exploitable.
A common source for large stack growth are calls to
`alloca` and related functions such as
`strdupa`. These functions should be avoided
because of the lack of error checking. (They can be used safely
if the allocated size is less than the page size (typically,
4096 bytes), but this case is relatively rare.) Additionally,
relying on `alloca` makes it more difficult
to reorganize the code because it is not allowed to use the
pointer after the function calling `alloca`
has returned, even if this function has been inlined into its
caller.
Similar concerns apply to *variable-length
arrays* (VLAs), a feature of the C99 standard which
started as a GNU extension. For large objects exceeding the
page size, there is no error checking, either.
In both cases, negative or very large sizes can trigger a
stack-pointer wraparound, and the stack pointer and end up
pointing into caller stack frames, which is fatal and can be
exploitable.
If you want to use `alloca` or VLAs for
performance reasons, consider using a small on-stack array (less
than the page size, large enough to fulfill most requests). If
the requested size is small enough, use the on-stack array.
Otherwise, call `malloc`. When exiting the
function, check if `malloc` had been called,
and free the buffer as needed.
[[sect-Defensive_Coding-C-Allocators-Arrays]]
=== Array Allocation
When allocating arrays, it is important to check for overflows.
The `calloc` function performs such checks.
If `malloc` or `realloc`
is used, the size check must be written manually. For instance,
to allocate an array of `n` elements of type
`T`, check that the requested size is not
greater than `((size_t) -1) / sizeof(T)`. See
<<sect-Defensive_Coding-C-Arithmetic>>.
[[sect-Defensive_Coding-C-Allocators-Custom]]
=== Custom Memory Allocators
Custom memory allocates come in two forms: replacements for
`malloc`, and completely different interfaces
for memory management. Both approaches can reduce the
effectiveness of [application]*valgrind* and similar
tools, and the heap corruption detection provided by GNU libc, so
they should be avoided.
Memory allocators are difficult to write and contain many
performance and security pitfalls.
* When computing array sizes or rounding up allocation
requests (to the next allocation granularity, or for
alignment purposes), checks for arithmetic overflow are
required.
* Size computations for array allocations need overflow
checking. See <<sect-Defensive_Coding-C-Allocators-Arrays>>.
* It can be difficult to beat well-tuned general-purpose
allocators. In micro benchmarks, pool allocators can show
huge wins, and size-specific pools can reduce internal
fragmentation. But often, utilization of individual pools
is poor, and external fragmentation increases the overall
memory usage.
=== Conservative Garbage Collection
Garbage collection can be an alternative to explicit memory
management using `malloc` and
`free`. The Boehm-Dehmers-Weiser allocator
can be used from C programs, with minimal type annotations.
Performance is competitive with `malloc` on
64-bit architectures, especially for multi-threaded programs.
The stop-the-world pauses may be problematic for some real-time
applications, though.
However, using a conservative garbage collector may reduce
opportunities for code reduce because once one library in a
program uses garbage collection, the whole process memory needs
to be subject to it, so that no pointers are missed. The
Boehm-Dehmers-Weiser collector also reserves certain signals for
internal use, so it is not fully transparent to the rest of the
program.

View file

@ -0,0 +1,216 @@
:experimental:
[[sect-Defensive_Coding-C-Language]]
== The Core Language
C provides no memory safety. Most recommendations in this section
deal with this aspect of the language.
[[sect-Defensive_Coding-C-Undefined]]
=== Undefined Behavior
Some C constructs are defined to be undefined by the C standard.
This does not only mean that the standard does not describe
what happens when the construct is executed. It also allows
optimizing compilers such as GCC to assume that this particular
construct is never reached. In some cases, this has caused
GCC to optimize security checks away. (This is not a flaw in GCC
or the C language. But C certainly has some areas which are more
difficult to use than others.)
Common sources of undefined behavior are:
* out-of-bounds array accesses
* null pointer dereferences
* overflow in signed integer arithmetic
[[sect-Defensive_Coding-C-Pointers]]
=== Recommendations for Pointers and Array Handling
Always keep track of the size of the array you are working with.
Often, code is more obviously correct when you keep a pointer
past the last element of the array, and calculate the number of
remaining elements by substracting the current position from
that pointer. The alternative, updating a separate variable
every time when the position is advanced, is usually less
obviously correct.
<<ex-Defensive_Coding-C-Pointers-remaining>>
shows how to extract Pascal-style strings from a character
buffer. The two pointers kept for length checks are
`inend` and `outend`.
`inp` and `outp` are the
respective positions.
The number of input bytes is checked using the expression
`len > (size_t)(inend - inp)`.
The cast silences a compiler warning;
`inend` is always larger than
`inp`.
[[ex-Defensive_Coding-C-Pointers-remaining]]
.Array processing in C
====
[source,c]
----
include::../snippets/C-Pointers-remaining.adoc[]
----
====
It is important that the length checks always have the form
`len > (size_t)(inend - inp)`, where
`len` is a variable of type
`size_t` which denotes the *total*
number of bytes which are about to be read or written next. In
general, it is not safe to fold multiple such checks into one,
as in `len1 + len2 > (size_t)(inend - inp)`,
because the expression on the left can overflow or wrap around
(see <<sect-Defensive_Coding-C-Arithmetic>>), and it
no longer reflects the number of bytes to be processed.
[[sect-Defensive_Coding-C-Arithmetic]]
=== Recommendations for Integer Arithmetic
Overflow in signed integer arithmetic is undefined. This means
that it is not possible to check for overflow after it happened,
see <<ex-Defensive_Coding-C-Arithmetic-bad>>.
[[ex-Defensive_Coding-C-Arithmetic-bad]]
.Incorrect overflow detection in C
====
[source,c]
----
include::../snippets/C-Arithmetic-add.adoc[]
----
====
The following approaches can be used to check for overflow,
without actually causing it.
* Use a wider type to perform the calculation, check that the
result is within bounds, and convert the result to the
original type. All intermediate results must be checked in
this way.
* Perform the calculation in the corresponding unsigned type
and use bit fiddling to detect the overflow.
<<ex-Defensive_Coding-C-Arithmetic-add_unsigned>>
shows how to perform an overflow check for unsigned integer
addition. For three or more terms, all the intermediate
additions have to be checked in this way.
[[ex-Defensive_Coding-C-Arithmetic-add_unsigned]]
.Overflow checking for unsigned addition
====
[source,c]
----
include::../snippets/C-Arithmetic-add_unsigned.adoc[]
----
====
* Compute bounds for acceptable input values which are known
to avoid overflow, and reject other values. This is the
preferred way for overflow checking on multiplications,
see <<ex-Defensive_Coding-C-Arithmetic-mult>>.
[[ex-Defensive_Coding-C-Arithmetic-mult]]
.Overflow checking for unsigned multiplication
====
[source,c]
----
include::../snippets/C-Arithmetic-mult.adoc[]
----
====
Basic arithmetic operations are commutative, so for bounds checks,
there are two different but mathematically equivalent
expressions. Sometimes, one of the expressions results in
better code because parts of it can be reduced to a constant.
This applies to overflow checks for multiplication `a *
b` involving a constant `a`, where the
expression is reduced to `b > C` for some
constant `C` determined at compile time. The
other expression, `b && a > ((unsigned)-1) /
b`, is more difficult to optimize at compile time.
When a value is converted to a signed integer, GCC always
chooses the result based on 2's complement arithmetic. This GCC
extension (which is also implemented by other compilers) helps a
lot when implementing overflow checks.
Sometimes, it is necessary to compare unsigned and signed
integer variables. This results in a compiler warning,
*comparison between signed and unsigned integer
expressions*, because the comparison often gives
unexpected results for negative values. When adding a cast,
make sure that negative values are covered properly. If the
bound is unsigned and the checked quantity is signed, you should
cast the checked quantity to an unsigned type as least as wide
as either operand type. As a result, negative values will fail
the bounds check. (You can still check for negative values
separately for clarity, and the compiler will optimize away this
redundant check.)
Legacy code should be compiled with the [option]`-fwrapv`
GCC option. As a result, GCC will provide 2's complement
semantics for integer arithmetic, including defined behavior on
integer overflow.
[[sect-Defensive_Coding-C-Globals]]
=== Global Variables
Global variables should be avoided because they usually lead to
thread safety hazards. In any case, they should be declared
`static`, so that access is restricted to a
single translation unit.
Global constants are not a problem, but declaring them can be
tricky. <<ex-Defensive_Coding-C-Globals-String_Array>>
shows how to declare a constant array of constant strings.
The second `const` is needed to make the
array constant, and not just the strings. It must be placed
after the `*`, and not before it.
[[ex-Defensive_Coding-C-Globals-String_Array]]
.Declaring a constant array of constant strings
====
[source,c]
----
include::../snippets/C-Globals-String_Array.adoc[]
----
====
Sometimes, static variables local to functions are used as a
replacement for proper memory management. Unlike non-static
local variables, it is possible to return a pointer to static
local variables to the caller. But such variables are
well-hidden, but effectively global (just as static variables at
file scope). It is difficult to add thread safety afterwards if
such interfaces are used. Merely dropping the
`static` keyword in such cases leads to
undefined behavior.
Another source for static local variables is a desire to reduce
stack space usage on embedded platforms, where the stack may
span only a few hundred bytes. If this is the only reason why
the `static` keyword is used, it can just be
dropped, unless the object is very large (larger than
128 kilobytes on 32-bit platforms). In the latter case, it is
recommended to allocate the object using
`malloc`, to obtain proper array checking, for
the same reasons outlined in <<sect-Defensive_Coding-C-Allocators-alloca>>.

View file

@ -0,0 +1,287 @@
:experimental:
include::{partialsdir}/entities.adoc[]
[[sect-Defensive_Coding-C-Libc]]
== The C Standard Library
Parts of the C standard library (and the UNIX and GNU extensions)
are difficult to use, so you should avoid them.
Please check the applicable documentation before using the
recommended replacements. Many of these functions allocate
buffers using `malloc` which your code must
deallocate explicitly using `free`.
[[sect-Defensive_Coding-C-Absolutely-Banned]]
=== Absolutely Banned Interfaces
The functions listed below must not be used because they are
almost always unsafe. Use the indicated replacements instead.
* `gets`
⟶ `fgets`
* `getwd`
⟶ `getcwd`
or `get_current_dir_name`
* `readdir_r` ⟶ `readdir`
* `realpath` (with a non-NULL second parameter)
⟶ `realpath` with NULL as the second parameter,
or `canonicalize_file_name`
The constants listed below must not be used, either. Instead,
code must allocate memory dynamically and use interfaces with
length checking.
* `NAME_MAX` (limit not actually enforced by
the kernel)
* `PATH_MAX` (limit not actually enforced by
the kernel)
* `_PC_NAME_MAX` (This limit, returned by the
`pathconf` function, is not enforced by
the kernel.)
* `_PC_PATH_MAX` (This limit, returned by the
`pathconf` function, is not enforced by
the kernel.)
The following structure members must not be used.
* `f_namemax` in `struct
statvfs` (limit not actually enforced by the kernel,
see `_PC_NAME_MAX` above)
[[sect-Defensive_Coding-C-Avoid]]
=== Functions to Avoid
The following string manipulation functions can be used securely
in principle, but their use should be avoided because they are
difficult to use correctly. Calls to these functions can be
replaced with `asprintf` or
`vasprintf`. (For non-GNU targets, these
functions are available from Gnulib.) In some cases, the
`snprintf` function might be a suitable
replacement, see <<sect-Defensive_Coding-C-String-Functions-Length>>.
* `sprintf`
* `strcat`
* `strcpy`
* `vsprintf`
Use the indicated replacements for the functions below.
* `alloca` ⟶
`malloc` and `free`
(see <<sect-Defensive_Coding-C-Allocators-alloca>>)
* `putenv` ⟶
explicit `envp` argument in process creation
(see <<sect-Defensive_Coding-Tasks-Processes-environ>>)
* `setenv` ⟶
explicit `envp` argument in process creation
(see <<sect-Defensive_Coding-Tasks-Processes-environ>>)
* `strdupa` ⟶
`strdup` and `free`
(see <<sect-Defensive_Coding-C-Allocators-alloca>>)
* `strndupa` ⟶
`strndup` and `free`
(see <<sect-Defensive_Coding-C-Allocators-alloca>>)
* `system` ⟶
`posix_spawn`
or `fork`pass:attributes[{blank}]/pass:attributes[{blank}]`execve`pass:attributes[{blank}]/
(see <<sect-Defensive_Coding-Tasks-Processes-execve>>)
* `unsetenv` ⟶
explicit `envp` argument in process creation
(see <<sect-Defensive_Coding-Tasks-Processes-environ>>)
[[sect-Defensive_Coding-C-String-Functions-Length]]
=== String Functions with Explicit Length Arguments
The C run-time library provides string manipulation functions
which not just look for NUL characters for string termination,
but also honor explicit lengths provided by the caller.
However, these functions evolved over a long period of time, and
the lengths mean different things depending on the function.
[[sect-Defensive_Coding-C-Libc-snprintf]]
==== `snprintf`
The `snprintf` function provides a way to
construct a string in a statically-sized buffer. (If the buffer
size is allocated on the heap, consider use
`asprintf` instead.)
[source,c]
----
include::../snippets/C-String-Functions-snprintf.adoc[]
----
The second argument to the `snprintf` call
should always be the size of the buffer in the first argument
(which should be a character array). Elaborate pointer and
length arithmetic can introduce errors and nullify the
security benefits of `snprintf`.
In particular, `snprintf` is not well-suited
to constructing a string iteratively, by appending to an
existing buffer. `snprintf` returns one of
two values, `-1` on errors, or the number of
characters which *would have been written to the
buffer if the buffer were large enough*. This means
that adding the result of `snprintf` to the
buffer pointer to skip over the characters just written is
incorrect and risky. However, as long as the length argument
is not zero, the buffer will remain null-terminated. <<ex-Defensive_Coding-C-String-Functions-snprintf-incremental>>
works because `end -current > 0` is a loop
invariant. After the loop, the result string is in the
`buf` variable.
[[ex-Defensive_Coding-C-String-Functions-snprintf-incremental]]
.Repeatedly writing to a buffer using `snprintf`
====
[source,c]
----
include::../snippets/C-String-Functions-snprintf-incremental.adoc[]
----
====
If you want to avoid the call to `strlen`
for performance reasons, you have to check for a negative
return value from `snprintf` and also check
if the return value is equal to the specified buffer length or
larger. Only if neither condition applies, you may advance
the pointer to the start of the write buffer by the number
return by `snprintf`. However, this
optimization is rarely worthwhile.
Note that it is not permitted to use the same buffer both as
the destination and as a source argument.
[[sect-Defensive_Coding-C-Libc-vsnprintf]]
==== `vsnprintf` and Format Strings
If you use `vsnprintf` (or
`vasprintf` or even
`snprintf`) with a format string which is
not a constant, but a function argument, it is important to
annotate the function with a `format`
function attribute, so that GCC can warn about misuse of your
function (see <<ex-Defensive_Coding-C-String-Functions-format-Attribute>>).
[[ex-Defensive_Coding-C-String-Functions-format-Attribute]]
.The `format` function attribute
====
[source,c]
----
include::../snippets/C-String-Functions-format.adoc[]
----
====
[[sect-Defensive_Coding-C-Libc-strncpy]]
==== `strncpy`
The `strncpy` function does not ensure that
the target buffer is null-terminated. A common idiom for
ensuring NUL termination is:
[source,c]
----
include::../snippets/C-String-Functions-strncpy.adoc[]
----
Another approach uses the `strncat`
function for this purpose:
[source,c]
----
include::../snippets/C-String-Functions-strncat-as-strncpy.adoc[]
----
[[sect-Defensive_Coding-C-Libc-strncat]]
==== `strncat`
The length argument of the `strncat`
function specifies the maximum number of characters copied
from the source buffer, excluding the terminating NUL
character. This means that the required number of bytes in
the destination buffer is the length of the original string,
plus the length argument in the `strncat`
call, plus one. Consequently, this function is rarely
appropriate for performing a length-checked string operation,
with the notable exception of the `strcpy`
emulation described in <<sect-Defensive_Coding-C-Libc-strncpy>>.
To implement a length-checked string append, you can use an
approach similar to <<ex-Defensive_Coding-C-String-Functions-snprintf-incremental>>:
[source,c]
----
include::../snippets/C-String-Functions-strncat-emulation.adoc[]
----
In many cases, including this one, the string concatenation
can be avoided by combining everything into a single format
string:
[source,c]
----
include::../snippets/C-String-Functions-strncat-merged.adoc[]
----
But you should must not dynamically construct format strings
to avoid concatenation because this would prevent GCC from
type-checking the argument lists.
It is not possible to use format strings like
`"%s%s"` to implement concatenation, unless
you use separate buffers. `snprintf` does
not support overlapping source and target strings.
==== `strlcpy` and `strlcat`
Some systems support `strlcpy` and
`strlcat` functions which behave this way,
but these functions are not part of GNU libc.
`strlcpy` is often replaced with
`snprintf` with a `"%s"`
format string. See <<sect-Defensive_Coding-C-Libc-strncpy>> for a caveat
related to the `snprintf` return value.
To emulate `strlcat`, use the approach
described in <<sect-Defensive_Coding-C-Libc-strncat>>.
==== ISO C11 Annex K *pass:attributes[{blank}]`_s` functions
ISO C11 adds another set of length-checking functions, but GNU
libc currently does not implement them.
==== Other `strn*` and `stpn*` functions
GNU libc contains additional functions with different variants
of length checking. Consult the documentation before using
them to find out what the length actually means.

View file

@ -0,0 +1,53 @@
:experimental:
[[sect-Defensive_Coding-C-Other]]
== Other C-related Topics
[[sect-Defensive_Coding-C-Wrapper-Functions]]
=== Wrapper Functions
Some libraries provide wrappers for standard library functions.
Common cases include allocation functions such as
`xmalloc` which abort the process on
allocation failure (instead of returning a
`NULL` pointer), or alternatives to relatively
recent library additions such as `snprintf`
(along with implementations for systems which lack them).
In general, such wrappers are a bad idea, particularly if they
are not implemented as inline functions or preprocessor macros.
The compiler lacks knowledge of such wrappers outside the
translation unit which defines them, which means that some
optimizations and security checks are not performed. Adding
`__attribute__` annotations to function
declarations can remedy this to some extent, but these
annotations have to be maintained carefully for feature parity
with the standard implementation.
At the minimum, you should apply these attributes:
* If you wrap function which accepts are GCC-recognized format
string (for example, a `printf`-style
function used for logging), you should add a suitable
`format` attribute, as in <<ex-Defensive_Coding-C-String-Functions-format-Attribute>>.
* If you wrap a function which carries a
`warn_unused_result` attribute and you
propagate its return value, your wrapper should be declared
with `warn_unused_result` as well.
* Duplicating the buffer length checks based on the
`__builtin_object_size` GCC builtin is
desirable if the wrapper processes arrays. (This
functionality is used by the
`-D_FORTIFY_SOURCE=2` checks to guard
against static buffer overflows.) However, designing
appropriate interfaces and implementing the checks may not
be entirely straightforward.
For other attributes (such as `malloc`),
careful analysis and comparison with the compiler documentation
is required to check if propagating the attribute is
appropriate. Incorrectly applied attributes can result in
undesired behavioral changes in the compiled code.

View file

@ -0,0 +1,13 @@
:experimental:
[[chap-Defensive_Coding-C]]
= The C Programming Language
include::en-US/programming-languages/C-Language.adoc[]
include::en-US/programming-languages/C-Libc.adoc[]
include::en-US/programming-languages/C-Allocators.adoc[]
include::en-US/programming-languages/C-Other.adoc[]

View file

@ -0,0 +1,133 @@
:experimental:
[[sect-Defensive_Coding-CXX-Language]]
== The Core Language
C++ includes a large subset of the C language. As far as the C
subset is used, the recommendations in <<chap-Defensive_Coding-C>> apply.
=== Array Allocation with `operator new[]`
For very large values of `n`, an expression
like `new T[n]` can return a pointer to a heap
region which is too small. In other words, not all array
elements are actually backed with heap memory reserved to the
array. Current GCC versions generate code that performs a
computation of the form `sizeof(T) * size_t(n) +
cookie_size`, where `cookie_size` is
currently at most 8. This computation can overflow, and GCC
versions prior to 4.8 generated code which did not detect this.
(Fedora 18 was the first release which fixed this in GCC.)
The `std::vector` template can be used instead
an explicit array allocation. (The GCC implementation detects
overflow internally.)
If there is no alternative to `operator new[]`
and the sources will be compiled with older GCC versions, code
which allocates arrays with a variable length must check for
overflow manually. For the `new T[n]` example,
the size check could be `n || (n > 0 && n >
(size_t(-1) - 8) / sizeof(T))`. (See <<sect-Defensive_Coding-C-Arithmetic>>.) If there are
additional dimensions (which must be constants according to the
{cpp} standard), these should be included as factors in the
divisor.
These countermeasures prevent out-of-bounds writes and potential
code execution. Very large memory allocations can still lead to
a denial of service. <<sect-Defensive_Coding-Tasks-Serialization-Decoders>>
contains suggestions for mitigating this problem when processing
untrusted data.
See <<sect-Defensive_Coding-C-Allocators-Arrays>>
for array allocation advice for C-style memory allocation.
=== Overloading
Do not overload functions with versions that have different
security characteristics. For instance, do not implement a
function `strcat` which works on
`std::string` arguments. Similarly, do not name
methods after such functions.
=== ABI compatibility and preparing for security updates
A stable binary interface (ABI) is vastly preferred for security
updates. Without a stable ABI, all reverse dependencies need
recompiling, which can be a lot of work and could even be
impossible in some cases. Ideally, a security update only
updates a single dynamic shared object, and is picked up
automatically after restarting affected processes.
Outside of extremely performance-critical code, you should
ensure that a wide range of changes is possible without breaking
ABI. Some very basic guidelines are:
* Avoid inline functions.
* Use the pointer-to-implementation idiom.
* Try to avoid templates. Use them if the increased type
safety provides a benefit to the programmer.
* Move security-critical code out of templated code, so that
it can be patched in a central place if necessary.
The KDE project publishes a document with more extensive
guidelines on ABI-preserving changes to {cpp} code, link:++https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B%2B++[Policies/Binary
Compatibility Issues With {cpp}]
(*d-pointer* refers to the
pointer-to-implementation idiom).
[[sect-Defensive_Coding-CXX-Language-CXX11]]
=== {cpp}0X and {cpp}11 Support
GCC offers different language compatibility modes:
* [option]`-std=c++98` for the original 1998 {cpp}
standard
* [option]`-std=c++03` for the 1998 standard with the
changes from the TR1 technical report
* [option]`-std=c++11` for the 2011 {cpp} standard. This
option should not be used.
* [option]`-std=c++0x` for several different versions
of {cpp}11 support in development, depending on the GCC
version. This option should not be used.
For each of these flags, there are variants which also enable
GNU extensions (mostly language features also found in C99 or
C11):
* [option]`-std=gnu++98`
* [option]`-std=gnu++03`
* [option]`-std=gnu++11`
Again, [option]`-std=gnu++11` should not be used.
If you enable {cpp}11 support, the ABI of the standard {cpp} library
`libstdc++` will change in subtle ways.
Currently, no {cpp} libraries are compiled in {cpp}11 mode, so if
you compile your code in {cpp}11 mode, it will be incompatible
with the rest of the system. Unfortunately, this is also the
case if you do not use any {cpp}11 features. Currently, there is
no safe way to enable {cpp}11 mode (except for freestanding
applications).
The meaning of {cpp}0X mode changed from GCC release to GCC
release. Earlier versions were still ABI-compatible with {cpp}98
mode, but in the most recent versions, switching to {cpp}0X mode
activates {cpp}11 support, with its compatibility problems.
Some {cpp}11 features (or approximations thereof) are available
with TR1 support, that is, with [option]`-std=c++03` or
[option]`-std=gnu++03` and in the
`<tr1/*>` header files. This includes
`std::tr1::shared_ptr` (from
`<tr1/memory>`) and
`std::tr1::function` (from
`<tr1/functional>`). For other {cpp}11
features, the Boost {cpp} library contains replacements.

View file

@ -0,0 +1,190 @@
:experimental:
[[sect-Defensive_Coding-CXX-Std]]
== The C++ Standard Library
The C++ standard library includes most of its C counterpart
by reference, see <<sect-Defensive_Coding-C-Libc>>.
[[sect-Defensive_Coding-CXX-Std-Functions]]
=== Functions That Are Difficult to Use
This section collects functions and function templates which are
part of the standard library and are difficult to use.
[[sect-Defensive_Coding-CXX-Std-Functions-Unpaired_Iterators]]
==== Unpaired Iterators
Functions which use output operators or iterators which do not
come in pairs (denoting ranges) cannot perform iterator range
checking.
(See <<sect-Defensive_Coding-CXX-Std-Iterators>>)
Function templates which involve output iterators are
particularly dangerous:
* `std::copy`
* `std::copy_backward`
* `std::copy_if`
* `std::move` (three-argument variant)
* `std::move_backward`
* `std::partition_copy_if`
* `std::remove_copy`
* `std::remove_copy_if`
* `std::replace_copy`
* `std::replace_copy_if`
* `std::swap_ranges`
* `std::transform`
In addition, `std::copy_n`,
`std::fill_n` and
`std::generate_n` do not perform iterator
checking, either, but there is an explicit count which has to be
supplied by the caller, as opposed to an implicit length
indicator in the form of a pair of forward iterators.
These output-iterator-expecting functions should only be used
with unlimited-range output iterators, such as iterators
obtained with the `std::back_inserter`
function.
Other functions use single input or forward iterators, which can
read beyond the end of the input range if the caller is not careful:
* `std::equal`
* `std::is_permutation`
* `std::mismatch`
[[sect-Defensive_Coding-CXX-Std-String]]
=== String Handling with `std::string`
The `std::string` class provides a convenient
way to handle strings. Unlike C strings,
`std::string` objects have an explicit length
(and can contain embedded NUL characters), and storage for its
characters is managed automatically. This section discusses
`std::string`, but these observations also
apply to other instances of the
`std::basic_string` template.
The pointer returned by the `data()` member
function does not necessarily point to a NUL-terminated string.
To obtain a C-compatible string pointer, use
`c_str()` instead, which adds the NUL
terminator.
The pointers returned by the `data()` and
`c_str()` functions and iterators are only
valid until certain events happen. It is required that the
exact `std::string` object still exists (even
if it was initially created as a copy of another string object).
Pointers and iterators are also invalidated when non-const
member functions are called, or functions with a non-const
reference parameter. The behavior of the GCC implementation
deviates from that required by the {cpp} standard if multiple
threads are present. In general, only the first call to a
non-const member function after a structural modification of the
string (such as appending a character) is invalidating, but this
also applies to member function such as the non-const version of
`begin()`, in violation of the {cpp} standard.
Particular care is necessary when invoking the
`c_str()` member function on a temporary
object. This is convenient for calling C functions, but the
pointer will turn invalid as soon as the temporary object is
destroyed, which generally happens when the outermost expression
enclosing the expression on which `c_str()`
is called completes evaluation. Passing the result of
`c_str()` to a function which does not store
or otherwise leak that pointer is safe, though.
Like with `std::vector` and
`std::array`, subscribing with
`operator[]` does not perform bounds checks.
Use the `at(size_type)` member function
instead. See <<sect-Defensive_Coding-CXX-Std-Subscript>>.
Furthermore, accessing the terminating NUL character using
`operator[]` is not possible. (In some
implementations, the `c_str()` member function
writes the NUL character on demand.)
Never write to the pointers returned by
`data()` or `c_str()`
after casting away `const`. If you need a
C-style writable string, use a
`std::vector<char>` object and its
`data()` member function. In this case, you
have to explicitly add the terminating NUL character.
GCC's implementation of `std::string` is
currently based on reference counting. It is expected that a
future version will remove the reference counting, due to
performance and conformance issues. As a result, code that
implicitly assumes sharing by holding to pointers or iterators
for too long will break, resulting in run-time crashes or worse.
On the other hand, non-const iterator-returning functions will
no longer give other threads an opportunity for invalidating
existing iterators and pointers because iterator invalidation
does not depend on sharing of the internal character array
object anymore.
[[sect-Defensive_Coding-CXX-Std-Subscript]]
=== Containers and `operator[]`
Many sequence containers similar to `std::vector`
provide both `operator[](size_type)` and a
member function `at(size_type)`. This applies
to `std::vector` itself,
`std::array`, `std::string`
and other instances of `std::basic_string`.
`operator[](size_type)` is not required by the
standard to perform bounds checking (and the implementation in
GCC does not). In contrast, `at(size_type)`
must perform such a check. Therefore, in code which is not
performance-critical, you should prefer
`at(size_type)` over
`operator[](size_type)`, even though it is
slightly more verbose.
The `front()` and `back()`
member functions are undefined if a vector object is empty. You
can use `vec.at(0)` and
`vec.at(vec.size() - 1)` as checked
replacements. For an empty vector, `data()` is
defined; it returns an arbitrary pointer, but not necessarily
the NULL pointer.
[[sect-Defensive_Coding-CXX-Std-Iterators]]
=== Iterators
Iterators do not perform any bounds checking. Therefore, all
functions that work on iterators should accept them in pairs,
denoting a range, and make sure that iterators are not moved
outside that range. For forward iterators and bidirectional
iterators, you need to check for equality before moving the
first or last iterator in the range. For random-access
iterators, you need to compute the difference before adding or
subtracting an offset. It is not possible to perform the
operation and check for an invalid operator afterwards.
Output iterators cannot be compared for equality. Therefore, it
is impossible to write code that detects that it has been
supplied an output area that is too small, and their use should
be avoided.
These issues make some of the standard library functions
difficult to use correctly, see <<sect-Defensive_Coding-CXX-Std-Functions-Unpaired_Iterators>>.

View file

@ -0,0 +1,8 @@
:experimental:
[[chap-Defensive_Coding-CXX]]
= The C++ Programming Language
include::en-US/programming-languages/CXX-Language.adoc[]
include::en-US/programming-languages/CXX-Std.adoc[]

View file

@ -0,0 +1,110 @@
:experimental:
[[chap-Defensive_Coding-Go]]
= The Go Programming Language
This chapter contains language-specific recommendations for Go.
[[chap-Defensive_Coding-Go-Memory_Safety]]
== Memory Safety
Go provides memory safety, but only if the program is not executed
in parallel (that is, `GOMAXPROCS` is not larger than
`1`). The reason is that interface values and
slices consist of multiple words are not updated atomically.
Another thread of execution can observe an inconsistent pairing
between type information and stored value (for interfaces) or
pointer and length (for slices), and such inconsistency can lead
to a memory safety violation.
Code which does not run in parallel and does not use the
`unsafe` package (or other packages which expose
unsafe constructs) is memory-safe. For example, invalid casts and
out-of-range subscripting cause panics at run time.
Keep in mind that finalization can introduce parallelism because
finalizers are executed concurrently, potentially interleaved with
the rest of the program.
[[chap-Defensive_Coding-Go-Error_Handling]]
== Error Handling
Only a few common operations (such as pointer dereference, integer
division, array subscripting) trigger exceptions in Go, called
*panics*. Most interfaces in the standard
library use a separate return value of type
`error` to signal error.
Not checking error return values can lead to incorrect operation
and data loss (especially in the case of writes, using interfaces
such as `io.Writer`).
The correct way to check error return values depends on the
function or method being called. In the majority of cases, the
first step after calling a function should be an error check
against the `nil` value, handling any encountered
error. See <<ex-Defensive_Coding-Go-Error_Handling-Regular>> for
details.
[[ex-Defensive_Coding-Go-Error_Handling-Regular]]
.Regular error handling in Go
====
[source,go]
----
include::../snippets/Go-Error_Handling-Regular.adoc[]
----
====
However, with `io.Reader`,
`io.ReaderAt` and related interfaces, it is
necessary to check for a non-zero number of read bytes first, as
shown in <<ex-Defensive_Coding-Go-Error_Handling-IO>>. If this
pattern is not followed, data loss may occur. This is due to the
fact that the `io.Reader` interface permits
returning both data and an error at the same time.
[[ex-Defensive_Coding-Go-Error_Handling-IO]]
.Read error handling in Go
====
[source,go]
----
include::../snippets/Go-Error_Handling-IO.adoc[]
----
====
[[chap-Defensive_Coding-Go-Garbage_Collector]]
== Garbage Collector
Older Go releases (before Go 1.3) use a conservative garbage
collector without blacklisting. This means that data blobs can
cause retention of unrelated data structures because the data is
conservatively interpreted as pointers. This phenomenon can be
triggered accidentally on 32-bit architectures and is more likely
to occur if the heap grows larger. On 64-bit architectures, it
may be possible to trigger it deliberately—it is unlikely to occur
spontaneously.
[[chap-Defensive_Coding-Go-Marshaling]]
== Marshaling and Unmarshaling
Several packages in the `encoding` hierarchy
provide support for serialization and deserialization. The usual
caveats apply (see
<<chap-Defensive_Coding-Tasks-Serialization>>).
As an additional precaution, the `Unmarshal`
and `Decode` functions should only be used with
fresh values in the `interface{}` argument. This
is due to the way defaults for missing values are implemented:
During deserialization, missing value do not result in an error,
but the original value is preserved. Using a fresh value (with
suitable default values if necessary) ensures that data from a
previous deserialization operation does not leak into the current
one. This is especially relevant when structs are deserialized.

View file

@ -0,0 +1,252 @@
:experimental:
[[sect-Defensive_Coding-Java-Language]]
== The Core Language
Implementations of the Java programming language provide strong
memory safety, even in the presence of data races in concurrent
code. This prevents a large range of security vulnerabilities
from occurring, unless certain low-level features are used; see
<<sect-Defensive_Coding-Java-LowLevel>>.
[[sect-Defensive_Coding-Java-Language-ReadArray]]
=== Increasing Robustness when Reading Arrays
External data formats often include arrays, and the data is
stored as an integer indicating the number of array elements,
followed by this number of elements in the file or protocol data
unit. This length specified can be much larger than what is
actually available in the data source.
To avoid allocating extremely large amounts of data, you can
allocate a small array initially and grow it as you read more
data, implementing an exponential growth policy. See the
`readBytes(InputStream, int)` function in
<<ex-Defensive_Coding-Java-Language-ReadArray>>.
[[ex-Defensive_Coding-Java-Language-ReadArray]]
.Incrementally reading a byte array
====
[source,java]
----
include::../snippets/Java-Language-ReadArray.adoc[]
----
====
When reading data into arrays, hash maps or hash sets, use the
default constructor and do not specify a size hint. You can
simply add the elements to the collection as you read them.
[[sect-Defensive_Coding-Java-Language-Resources]]
=== Resource Management
Unlike C++, Java does not offer destructors which can deallocate
resources in a predictable fashion. All resource management has
to be manual, at the usage site. (Finalizers are generally not
usable for resource management, especially in high-performance
code; see <<sect-Defensive_Coding-Java-Language-Finalizers>>.)
The first option is the
`try`-`finally` construct, as
shown in <<ex-Defensive_Coding-Java-Language-Finally>>.
The code in the `finally` block should be as short as
possible and should not throw any exceptions.
[[ex-Defensive_Coding-Java-Language-Finally]]
.Resource management with a `try`-`finally` block
====
[source,java]
----
include::../snippets/Java-Finally.adoc[]
----
====
Note that the resource allocation happens
*outside* the `try` block,
and that there is no `null` check in the
`finally` block. (Both are common artifacts
stemming from IDE code templates.)
If the resource object is created freshly and implements the
`java.lang.AutoCloseable` interface, the code
in <<ex-Defensive_Coding-Java-Language-TryWithResource>> can be
used instead. The Java compiler will automatically insert the
`close()` method call in a synthetic
`finally` block.
[[ex-Defensive_Coding-Java-Language-TryWithResource]]
.Resource management using the `try`-with-resource construct
====
[source,java]
----
include::../snippets/Java-TryWithResource.adoc[]
----
====
To be compatible with the `try`-with-resource
construct, new classes should name the resource deallocation
method `close()`, and implement the
`AutoCloseable` interface (the latter breaking
backwards compatibility with Java 6). However, using the
`try`-with-resource construct with objects that
are not freshly allocated is at best awkward, and an explicit
`finally` block is usually the better approach.
In general, it is best to design the programming interface in
such a way that resource deallocation methods like
`close()` cannot throw any (checked or
unchecked) exceptions, but this should not be a reason to ignore
any actual error conditions.
[[sect-Defensive_Coding-Java-Language-Finalizers]]
=== Finalizers
Finalizers can be used a last-resort approach to free resources
which would otherwise leak. Finalization is unpredictable,
costly, and there can be a considerable delay between the last
reference to an object going away and the execution of the
finalizer. Generally, manual resource management is required;
see <<sect-Defensive_Coding-Java-Language-Resources>>.
Finalizers should be very short and should only deallocate
native or other external resources held directly by the object
being finalized. In general, they must use synchronization:
Finalization necessarily happens on a separate thread because it is
inherently concurrent. There can be multiple finalization
threads, and despite each object being finalized at most once,
the finalizer must not assume that it has exclusive access to
the object being finalized (in the `this`
pointer).
Finalizers should not deallocate resources held by other
objects, especially if those objects have finalizers on their
own. In particular, it is a very bad idea to define a finalizer
just to invoke the resource deallocation method of another object,
or overwrite some pointer fields.
Finalizers are not guaranteed to run at all. For instance, the
virtual machine (or the machine underneath) might crash,
preventing their execution.
Objects with finalizers are garbage-collected much later than
objects without them, so using finalizers to zero out key
material (to reduce its undecrypted lifetime in memory) may have
the opposite effect, keeping objects around for much longer and
prevent them from being overwritten in the normal course of
program execution.
For the same reason, code which allocates objects with
finalizers at a high rate will eventually fail (likely with a
`java.lang.OutOfMemoryError` exception) because
the virtual machine has finite resources for keeping track of
objects pending finalization. To deal with that, it may be
necessary to recycle objects with finalizers.
The remarks in this section apply to finalizers which are
implemented by overriding the `finalize()`
method, and to custom finalization using reference queues.
[[sect-Defensive_Coding-Java-Language-Exceptions]]
=== Recovering from Exceptions and Errors
Java exceptions come in three kinds, all ultimately deriving
from `java.lang.Throwable`:
* *Run-time exceptions* do not have to be
declared explicitly and can be explicitly thrown from any
code, by calling code which throws them, or by triggering an
error condition at run time, like division by zero, or an
attempt at an out-of-bounds array access. These exceptions
derive from from the
`java.lang.RuntimeException` class (perhaps
indirectly).
* *Checked exceptions* have to be declared
explicitly by functions that throw or propagate them. They
are similar to run-time exceptions in other regards, except
that there is no language construct to throw them (except
the `throw` statement itself). Checked
exceptions are only present at the Java language level and
are only enforced at compile time. At run time, the virtual
machine does not know about them and permits throwing
exceptions from any code. Checked exceptions must derive
(perhaps indirectly) from the
`java.lang.Exception` class, but not from
`java.lang.RuntimeException`.
* *Errors* are exceptions which typically
reflect serious error conditions. They can be thrown at any
point in the program, and do not have to be declared (unlike
checked exceptions). In general, it is not possible to
recover from such errors; more on that below, in <<sect-Defensive_Coding-Java-Language-Exceptions-Errors>>.
Error classes derive (perhaps indirectly) from
`java.lang.Error`, or from
`java.lang.Throwable`, but not from
`java.lang.Exception`.
The general expection is that run-time errors are avoided by
careful programming (e.g., not dividing by zero). Checked
exception are expected to be caught as they happen (e.g., when
an input file is unexpectedly missing). Errors are impossible
to predict and can happen at any point and reflect that
something went wrong beyond all expectations.
[[sect-Defensive_Coding-Java-Language-Exceptions-Errors]]
==== The Difficulty of Catching Errors
Errors (that is, exceptions which do not (indirectly) derive
from `java.lang.Exception`), have the
peculiar property that catching them is problematic. There
are several reasons for this:
* The error reflects a failed consistenty check, for example,
`java.lang.AssertionError`.
* The error can happen at any point, resulting in
inconsistencies due to half-updated objects. Examples are
`java.lang.ThreadDeath`,
`java.lang.OutOfMemoryError` and
`java.lang.StackOverflowError`.
* The error indicates that virtual machine failed to provide
some semantic guarantees by the Java programming language.
`java.lang.ExceptionInInitializerError`
is an example—it can leave behind a half-initialized
class.
In general, if an error is thrown, the virtual machine should
be restarted as soon as possible because it is in an
inconsistent state. Continuing running as before can have
unexpected consequences. However, there are legitimate
reasons for catching errors because not doing so leads to even
greater problems.
Code should be written in a way that avoids triggering errors.
See <<sect-Defensive_Coding-Java-Language-ReadArray>>
for an example.
It is usually necessary to log errors. Otherwise, no trace of
the problem might be left anywhere, making it very difficult
to diagnose realted failures. Consequently, if you catch
`java.lang.Exception` to log and suppress all
unexpected exceptions (for example, in a request dispatching
loop), you should consider switching to
`java.lang.Throwable` instead, to also cover
errors.
The other reason mainly applies to such request dispatching
loops: If you do not catch errors, the loop stops looping,
resulting in a denial of service.
However, if possible, catching errors should be coupled with a
way to signal the requirement of a virtual machine restart.

View file

@ -0,0 +1,141 @@
:experimental:
[[sect-Defensive_Coding-Java-LowLevel]]
== Low-level Features of the Virtual Machine
[[sect-Defensive_Coding-Java-Reflection]]
=== Reflection and Private Parts
The `setAccessible(boolean)` method of the
`java.lang.reflect.AccessibleObject` class
allows a program to disable language-defined access rules for
specific constructors, methods, or fields. Once the access
checks are disabled, any code can use the
`java.lang.reflect.Constructor`,
`java.lang.reflect.Method`, or
`java.lang.reflect.Field` object to access the
underlying Java entity, without further permission checks. This
breaks encapsulation and can undermine the stability of the
virtual machine. (In contrast, without using the
`setAccessible(boolean)` method, this should
not happen because all the language-defined checks still apply.)
This feature should be avoided if possible.
[[sect-Defensive_Coding-Java-JNI]]
=== Java Native Interface (JNI)
The Java Native Interface allows calling from Java code
functions specifically written for this purpose, usually in C or
C++.
The transition between the Java world and the C world is not
fully type-checked, and the C code can easily break the Java
virtual machine semantics. Therefore, extra care is needed when
using this functionality.
To provide a moderate amount of type safety, it is recommended
to recreate the class-specific header file using
[application]*javah* during the build process,
include it in the implementation, and use the
[option]`-Wmissing-declarations` option.
Ideally, the required data is directly passed to static JNI
methods and returned from them, and the code and the C side does
not have to deal with accessing Java fields (or even methods).
When using `GetPrimitiveArrayCritical` or
`GetStringCritical`, make sure that you only
perform very little processing between the get and release
operations. Do not access the file system or the network, and
not perform locking, because that might introduce blocking.
When processing large strings or arrays, consider splitting the
computation into multiple sub-chunks, so that you do not prevent
the JVM from reaching a safepoint for extended periods of time.
If necessary, you can use the Java `long` type
to store a C pointer in a field of a Java class. On the C side,
when casting between the `jlong` value and the
pointer on the C side,
You should not try to perform pointer arithmetic on the Java
side (that is, you should treat pointer-carrying
`long` values as opaque). When passing a slice
of an array to the native code, follow the Java convention and
pass it as the base array, the integer offset of the start of
the slice, and the integer length of the slice. On the native
side, check the offset/length combination against the actual
array length, and use the offset to compute the pointer to the
beginning of the array.
[[ex-Defensive_Coding-Java-JNI-Pointers]]
.Array length checking in JNI code
====
[source,java]
----
include::../snippets/Java-JNI-Pointers.adoc[]
----
====
In any case, classes referring to native resources must be
declared `final`, and must not be serializeable
or cloneable. Initialization and mutation of the state used by
the native side must be controlled carefully. Otherwise, it
might be possible to create an object with inconsistent native
state which results in a crash (or worse) when used (or perhaps
only finalized) later. If you need both Java inheritance and
native resources, you should consider moving the native state to
a separate class, and only keep a reference to objects of that
class. This way, cloning and serialization issues can be
avoided in most cases.
If there are native resources associated with an object, the
class should have an explicit resource deallocation method
(<<sect-Defensive_Coding-Java-Language-Resources>>) and a
finalizer (<<sect-Defensive_Coding-Java-Language-Finalizers>>) as a
last resort. The need for finalization means that a minimum
amount of synchronization is needed. Code on the native side
should check that the object is not in a closed/freed state.
Many JNI functions create local references. By default, these
persist until the JNI-implemented method returns. If you create
many such references (e.g., in a loop), you may have to free
them using `DeleteLocalRef`, or start using
`PushLocalFrame` and
`PopLocalFrame`. Global references must be
deallocated with `DeleteGlobalRef`, otherwise
there will be a memory leak, just as with
`malloc` and `free`.
When throwing exceptions using `Throw` or
`ThrowNew`, be aware that these functions
return regularly. You have to return control manually to the
JVM.
Technically, the `JNIEnv` pointer is not
necessarily constant during the lifetime of your JNI module.
Storing it in a global variable is therefore incorrect.
Particularly if you are dealing with callbacks, you may have to
store the pointer in a thread-local variable (defined with
`__thread`). It is, however, best to avoid the
complexity of calling back into Java code.
Keep in mind that C/C++ and Java are different languages,
despite very similar syntax for expressions. The Java memory
model is much more strict than the C or C++ memory models, and
native code needs more synchronization, usually using JVM
facilities or POSIX threads mutexes. Integer overflow in Java
is defined, but in C/C++ it is not (for the
`jint` and `jlong` types).
[[sect-Defensive_Coding-Java-MiscUnsafe]]
=== `sun.misc.Unsafe`
The `sun.misc.Unsafe` class is unportable and
contains many functions explicitly designed to break Java memory
safety (for performance and debugging). If possible, avoid
using this class.

View file

@ -0,0 +1,256 @@
:experimental:
[[sect-Defensive_Coding-Java-SecurityManager]]
== Interacting with the Security Manager
The Java platform is largely implemented in the Java language
itself. Therefore, within the same JVM, code runs which is part
of the Java installation and which is trusted, but there might
also be code which comes from untrusted sources and is restricted
by the Java sandbox (to varying degrees). The *security
manager* draws a line between fully trusted, partially
trusted and untrusted code.
The type safety and accessibility checks provided by the Java
language and JVM would be sufficient to implement a sandbox.
However, only some Java APIs employ such a capabilities-based
approach. (The Java SE library contains many public classes with
public constructors which can break any security policy, such as
`java.io.FileOutputStream`.) Instead, critical
functionality is protected by *stack
inspection*: At a security check, the stack is walked
from top (most-nested) to bottom. The security check fails if a
stack frame for a method is encountered whose class lacks the
permission which the security check requires.
This simple approach would not allow untrusted code (which lacks
certain permissions) to call into trusted code while the latter
retains trust. Such trust transitions are desirable because they
enable Java as an implementation language for most parts of the
Java platform, including security-relevant code. Therefore, there
is a mechanism to mark certain stack frames as trusted (<<sect-Defensive_Coding-Java-SecurityManager-Privileged>>).
In theory, it is possible to run a Java virtual machine with a
security manager that acts very differently from this approach,
but a lot of code expects behavior very close to the platform
default (including many classes which are part of the OpenJDK
implementation).
[[sect-Defensive_Coding-Java-SecurityManager-Compatible]]
=== Security Manager Compatibility
A lot of code can run without any additional permissions at all,
with little changes. The following guidelines should help to
increase compatibility with a restrictive security manager.
* When retrieving system properties using
`System.getProperty(String)` or similar
methods, catch `SecurityException`
exceptions and treat the property as unset.
* Avoid unnecessary file system or network access.
* Avoid explicit class loading. Access to a suitable class
loader might not be available when executing as untrusted
code.
If the functionality you are implementing absolutely requires
privileged access and this functionality has to be used from
untrusted code (hopefully in a restricted and secure manner),
see <<sect-Defensive_Coding-Java-SecurityManager-Privileged>>.
[[sect-Defensive_Coding-Java-SecurityManager-Activate]]
=== Activating the Security Manager
The usual command to launch a Java application,
[command]`java`, does not activate the security manager.
Therefore, the virtual machine does not enforce any sandboxing
restrictions, even if explicitly requested by the code (for
example, as described in <<sect-Defensive_Coding-Java-SecurityManager-Unprivileged>>).
The [option]`-Djava.security.manager` option activates
the security manager, with the fairly restrictive default
policy. With a very permissive policy, most Java code will run
unchanged. Assuming the policy in <<ex-Defensive_Coding-Java-SecurityManager-GrantAll>>
has been saved in a file `grant-all.policy`,
this policy can be activated using the option
[option]`-Djava.security.policy=grant-all.policy` (in
addition to the [option]`-Djava.security.manager`
option).
[[ex-Defensive_Coding-Java-SecurityManager-GrantAll]]
.Most permissve OpenJDK policy file
====
[source,java]
----
grant {
permission java.security.AllPermission;
};
----
====
With this most permissive policy, the security manager is still
active, and explicit requests to drop privileges will be
honored.
[[sect-Defensive_Coding-Java-SecurityManager-Unprivileged]]
=== Reducing Trust in Code
The <<ex-Defensive_Coding-Java-SecurityManager-Unprivileged>> example
shows how to run a piece code of with reduced privileges.
[[ex-Defensive_Coding-Java-SecurityManager-Unprivileged]]
.Using the security manager to run code with reduced privileges
====
[source,java]
----
include::../snippets/Java-SecurityManager-Unprivileged.adoc[]
----
====
The example above does not add any additional permissions to the
`permissions` object. If such permissions are
necessary, code like the following (which grants read permission
on all files in the current directory) can be used:
[source,java]
----
include::../snippets/Java-SecurityManager-CurrentDirectory.adoc[]
----
[IMPORTANT]
====
Calls to the
`java.security.AccessController.doPrivileged()`
methods do not enforce any additional restriction if no
security manager has been set. Except for a few special
exceptions, the restrictions no longer apply if the
`doPrivileged()` has returned, even to
objects created by the code which ran with reduced privileges.
(This applies to object finalization in particular.)
The example code above does not prevent the called code from
calling the
`java.security.AccessController.doPrivileged()`
methods. This mechanism should be considered an additional
safety net, but it still can be used to prevent unexpected
behavior of trusted code. As long as the executed code is not
dynamic and came with the original application or library, the
sandbox is fairly effective.
The `context` argument in <<ex-Defensive_Coding-Java-SecurityManager-Unprivileged>>
is extremely important—otherwise, this code would increase
privileges instead of reducing them.
====
For activating the security manager, see <<sect-Defensive_Coding-Java-SecurityManager-Activate>>.
Unfortunately, this affects the virtual machine as a whole, so
it is not possible to do this from a library.
[[sect-Defensive_Coding-Java-SecurityManager-Privileged]]
=== Re-gaining Privileges
Ordinarily, when trusted code is called from untrusted code, it
loses its privileges (because of the untrusted stack frames
visible to stack inspection). The
`java.security.AccessController.doPrivileged()`
family of methods provides a controlled backdoor from untrusted
to trusted code.
[IMPORTANT]
====
By design, this feature can undermine the Java security model
and the sandbox. It has to be used very carefully. Most
sandbox vulnerabilities can be traced back to its misuse.
====
In essence, the `doPrivileged()` methods
cause the stack inspection to end at their call site. Untrusted
code further down the call stack becomes invisible to security
checks.
The following operations are common and safe to perform with
elevated privileges.
* Reading custom system properties with fixed names,
especially if the value is not propagated to untrusted code.
(File system paths including installation paths, host names
and user names are sometimes considered private information
and need to be protected.)
* Reading from the file system at fixed paths, either
determined at compile time or by a system property. Again,
leaking the file contents to the caller can be problematic.
* Accessing network resources under a fixed address, name or
URL, derived from a system property or configuration file,
information leaks not withstanding.
The <<ex-Defensive_Coding-Java-SecurityManager-Privileged>> example
shows how to request additional privileges.
[[ex-Defensive_Coding-Java-SecurityManager-Privileged]]
.Using the security manager to run code with increased privileges
====
[source,java]
----
include::../snippets/Java-SecurityManager-Privileged.adoc[]
----
====
Obviously, this only works if the class containing the call to
`doPrivileged()` is marked trusted (usually
because it is loaded from a trusted class loader).
When writing code that runs with elevated privileges, make sure
that you follow the rules below.
* Make the privileged code as small as possible. Perform as
many computations as possible before and after the
privileged code section, even if it means that you have to
define a new class to pass the data around.
* Make sure that you either control the inputs to the
privileged code, or that the inputs are harmless and cannot
affect security properties of the privileged code.
* Data that is returned from or written by the privileged code
must either be restricted (that is, it cannot be accessed by
untrusted code), or must be harmless. Otherwise, privacy
leaks or information disclosures which affect security
properties can be the result.
If the code calls back into untrusted code at a later stage (or
performs other actions under control from the untrusted caller),
you must obtain the original security context and restore it
before performing the callback, as in <<ex-Defensive_Coding-Java-SecurityManager-Callback>>.
(In this example, it would be much better to move the callback
invocation out of the privileged code section, of course.)
[[ex-Defensive_Coding-Java-SecurityManager-Callback]]
.Restoring privileges when invoking callbacks
====
[source,java]
----
include::../snippets/Java-SecurityManager-Callback.adoc[]
----
====

View file

@ -0,0 +1,11 @@
:experimental:
[[chap-Defensive_Coding-Java]]
= The Java Programming Language
include::en-US/programming-languages/Java-Language.adoc[]
include::en-US/programming-languages/Java-LowLevel.adoc[]
include::en-US/programming-languages/Java-SecurityManager.adoc[]

View file

@ -0,0 +1,51 @@
:experimental:
[[chap-Defensive_Coding-Python]]
= The Python Programming Language
Python provides memory safety by default, so low-level security
vulnerabilities are rare and typically needs fixing the Python
interpreter or standard library itself.
Other sections with Python-specific advice include:
* <<chap-Defensive_Coding-Tasks-Temporary_Files>>
* <<sect-Defensive_Coding-Tasks-Processes-Creation>>
* <<chap-Defensive_Coding-Tasks-Serialization>>, in
particular <<sect-Defensive_Coding-Tasks-Serialization-Library>>
* <<sect-Defensive_Coding-Tasks-Cryptography-Randomness>>
== Dangerous Standard Library Features
Some areas of the standard library, notably the
`ctypes` module, do not provide memory safety
guarantees comparable to the rest of Python. If such
functionality is used, the advice in <<sect-Defensive_Coding-C-Language>> should be followed.
== Run-time Compilation and Code Generation
The following Python functions and statements related to code
execution should be avoided:
* `compile`
* `eval`
* `exec`
* `execfile`
If you need to parse integers or floating point values, use the
`int` and `float`
functions instead of `eval`. Sandboxing
untrusted Python code does not work reliably.
== Sandboxing
The `rexec` Python module cannot safely sandbox
untrusted code and should not be used. The standard CPython
implementation is not suitable for sandboxing.

View file

@ -0,0 +1,395 @@
:experimental:
[[chap-Defensive_Coding-Shell]]
= Shell Programming and [application]*bash*
include::{partialsdir}/entities.adoc[]
This chapter contains advice about shell programming, specifically
in [application]*bash*. Most of the advice will apply
to scripts written for other shells because extensions such as
integer or array variables have been implemented there as well, with
comparable syntax.
[[sect-Defensive_Coding-Shell-Alternatives]]
== Consider Alternatives
Once a shell script is so complex that advice in this chapter
applies, it is time to step back and consider the question: Is
there a more suitable implementation language available?
For example, Python with its `subprocess` module
can be used to write scripts which are almost as concise as shell
scripts when it comes to invoking external programs, and Python
offers richer data structures, with less arcane syntax and more
consistent behavior.
[[sect-Defensive_Coding-Shell-Language]]
== Shell Language Features
The following sections cover subtleties concerning the shell
programming languages. They have been written with the
[application]*bash* shell in mind, but some of these
features apply to other shells as well.
Some of the features described may seem like implementation defects,
but these features have been replicated across multiple independent
implementations, so they now have to be considered part of the shell
programming language.
[[sect-Defensive_Coding-Shell-Parameter_Expansion]]
=== Parameter Expansion
The mechanism by which named shell variables and parameters are
expanded is called *parameter expansion*. The
most basic syntax is
“pass:attributes[{blank}]`$`pass:attributes[{blank}]pass:attributes[{blank}]*variable*pass:attributes[{blank}]” or
“pass:attributes[{blank}]`${`pass:attributes[{blank}]pass:attributes[{blank}]*variable*pass:attributes[{blank}]pass:attributes[{blank}]`}`pass:attributes[{blank}]”.
In almost all cases, a parameter expansion should be enclosed in
double quotation marks `"`pass:attributes[{blank}]…pass:attributes[{blank}]`"`.
[source,bash]
----
external-program "$arg1" "$arg2"
----
If the double quotation marks are omitted, the value of the
variable will be split according to the current value of the
`IFS` variable. This may allow the injection of
additional options which are then processed by
`external-program`.
Parameter expansion can use special syntax for specific features,
such as substituting defaults or performing string or array
operations. These constructs should not be used because they can
trigger arithmetic evaluation, which can result in code execution.
See <<sect-Defensive_Coding-Shell-Arithmetic>>.
[[sect-Defensive_Coding-Shell-Double_Expansion]]
=== Double Expansion
*Double expansion* occurs when, during the
expansion of a shell variable, not just the variable is expanded,
replacing it by its value, but the *value* of
the variable is itself is expanded as well. This can trigger
arbitrary code execution, unless the value of the variable is
verified against a restrictive pattern.
The evaluation process is in fact recursive, so a self-referential
expression can cause an out-of-memory condition and a shell crash.
Double expansion may seem like as a defect, but it is implemented
by many shells, and has to be considered an integral part of the
shell programming language. However, it does make writing robust
shell scripts difficult.
Double expansion can be requested explicitly with the
`eval` built-in command, or by invoking a
subshell with “pass:attributes[{blank}]`bash -c`pass:attributes[{blank}]”. These constructs
should not be used.
The following sections give examples of places where implicit
double expansion occurs.
[[sect-Defensive_Coding-Shell-Arithmetic]]
==== Arithmetic Evaluation
*Arithmetic evaluation* is a process by which
the shell computes the integer value of an expression specified
as a string. It is highly problematic for two reasons: It
triggers double expansion (see <<sect-Defensive_Coding-Shell-Double_Expansion>>), and the
language of arithmetic expressions is not self-contained. Some
constructs in arithmetic expressions (notably array subscripts)
provide a trapdoor from the restricted language of arithmetic
expressions to the full shell language, thus paving the way
towards arbitrary code execution. Due to double expansion,
input which is (indirectly) referenced from an arithmetic
expression can trigger execution of arbitrary code, which is
potentially harmful.
Arithmetic evaluation is triggered by the follow constructs:
* The *expression* in
“pass:attributes[{blank}]`$((`pass:attributes[{blank}]pass:attributes[{blank}]*expression*pass:attributes[{blank}]pass:attributes[{blank}]`))`pass:attributes[{blank}]”
is evaluated. This construct is called *arithmetic
expansion*.
* {blank}
+
“pass:attributes[{blank}]`$[`pass:attributes[{blank}]pass:attributes[{blank}]*expression*pass:attributes[{blank}]pass:attributes[{blank}]`]`pass:attributes[{blank}]”
is a deprecated syntax with the same effect.
* The arguments to the `let` shell built-in
are evaluated.
* {blank}
+
“pass:attributes[{blank}]`((`pass:attributes[{blank}]pass:attributes[{blank}]*expression*pass:attributes[{blank}]pass:attributes[{blank}]`))`pass:attributes[{blank}]”
is an alternative syntax for “pass:attributes[{blank}]`let` *expression*pass:attributes[{blank}]”.
* Conditional expressions surrounded by
“pass:attributes[{blank}]`[[`pass:attributes[{blank}]…pass:attributes[{blank}]`]]`pass:attributes[{blank}]” can trigger
arithmetic evaluation if certain operators such as
`-eq` are used. (The
`test` built-in does not perform arithmetic
evaluation, even with integer operators such as
`-eq`.)
+
The conditional expression
“pass:attributes[{blank}]`[[ $`pass:attributes[{blank}]pass:attributes[{blank}]*variable* `=~` *regexp* `]]`pass:attributes[{blank}]”
can be used for input validation, assuming that
*regexp* is a constant regular
expression.
See <<sect-Defensive_Coding-Shell-Input_Validation>>.
* Certain parameter expansions, for example
“pass:attributes[{blank}]`${`pass:attributes[{blank}]pass:attributes[{blank}]*variable*pass:attributes[{blank}]pass:attributes[{blank}]`[`pass:attributes[{blank}]pass:attributes[{blank}]*expression*pass:attributes[{blank}]pass:attributes[{blank}]`]}`pass:attributes[{blank}]”
(array indexing) or
“pass:attributes[{blank}]`${`pass:attributes[{blank}]pass:attributes[{blank}]*variable*pass:attributes[{blank}]pass:attributes[{blank}]`:`pass:attributes[{blank}]pass:attributes[{blank}]*expression*pass:attributes[{blank}]pass:attributes[{blank}]`}`pass:attributes[{blank}]”
(string slicing), trigger arithmetic evaluation of
*expression*.
* Assignment to array elements using
“pass:attributes[{blank}]*array_variable*pass:attributes[{blank}]pass:attributes[{blank}]`[`pass:attributes[{blank}]pass:attributes[{blank}]*subscript*pass:attributes[{blank}]pass:attributes[{blank}]`]=`pass:attributes[{blank}]pass:attributes[{blank}]*expression*pass:attributes[{blank}]”
triggers evaluation of *subscript*, but
not *expression*.
* The expressions in the arithmetic `for`
command,
“pass:attributes[{blank}]`for ((`pass:attributes[{blank}]pass:attributes[{blank}]*expression1*pass:attributes[{blank}]pass:attributes[{blank}]`;` *expression2*pass:attributes[{blank}]pass:attributes[{blank}]`;` *expression3*pass:attributes[{blank}]pass:attributes[{blank}]`)); do` *commands*pass:attributes[{blank}]pass:attributes[{blank}]`; done`pass:attributes[{blank}]”
are evaluated. This does not apply to the regular
for command,
“pass:attributes[{blank}]`for` *variable* `in` *list*pass:attributes[{blank}]pass:attributes[{blank}]`; do` *commands*pass:attributes[{blank}]pass:attributes[{blank}]`; done`pass:attributes[{blank}]”.
[IMPORTANT]
====
Depending on the [application]*bash* version, the
above list may be incomplete.
If faced with a situation where using such shell features
appears necessary, see <<sect-Defensive_Coding-Shell-Alternatives>>.
====
If it is impossible to avoid shell arithmetic on untrusted
inputs, refer to <<sect-Defensive_Coding-Shell-Input_Validation>>.
[[sect-Defensive_Coding-Shell-Types]]
==== Type declarations
[application]*bash* supports explicit type
declarations for shell variables:
[source,bash]
----
declare -i integer_variable
declare -a array_variable
declare -A assoc_array_variable
typeset -i integer_variable
typeset -a array_variable
typeset -A assoc_array_variable
local -i integer_variable
local -a array_variable
local -A assoc_array_variable
readonly -i integer_variable
readonly -a array_variable
readonly -A assoc_array_variable
----
Variables can also be declared as arrays by assigning them an
array expression, as in:
[source,bash]
----
array_variable=(1 2 3 4)
----
Some built-ins (such as `mapfile`) can
implicitly create array variables.
Such type declarations should not be used because assignment to
such variables (independent of the concrete syntax used for the
assignment) triggers arithmetic expansion (and thus double
expansion) of the right-hand side of the assignment operation.
See <<sect-Defensive_Coding-Shell-Arithmetic>>.
Shell scripts which use integer or array variables should be
rewritten in another, more suitable language. Se <<sect-Defensive_Coding-Shell-Alternatives>>.
[[sect-Defensive_Coding-Shell-Obscure]]
=== Other Obscurities
Obscure shell language features should not be used. Examples are:
* Exported functions (`export -f` or
`declare -f`).
* Function names which are not valid variable names, such as
“pass:attributes[{blank}]`module::function`pass:attributes[{blank}]”.
* The possibility to override built-ins or external commands
with shell functions.
* Changing the value of the `IFS` variable to
tokenize strings.
[[sect-Defensive_Coding-Shell-Invoke]]
== Invoking External Commands
When passing shell variables as single command line arguments,
they should always be surrounded by double quotes. See
<<sect-Defensive_Coding-Shell-Parameter_Expansion>>.
Care is required when passing untrusted values as positional
parameters to external commands. If the value starts with a hyphen
“pass:attributes[{blank}]`-`pass:attributes[{blank}]”, it may be interpreted by the external
command as an option. Depending on the external program, a
“pass:attributes[{blank}]`--`pass:attributes[{blank}]” argument stops option processing and treats
all following arguments as positional parameters. (Double quotes
are completely invisible to the command being invoked, so they do
not prevent variable values from being interpreted as options.)
Cleaning the environment before invoking child processes is
difficult to implement in script. [application]*bash*
keeps a hidden list of environment variables which do not correspond
to shell variables, and unsetting them from within a
[application]*bash* script is not possible. To reset
the environment, a script can re-run itself under the “pass:attributes[{blank}]`env
-i`pass:attributes[{blank}]” command with an additional parameter which indicates
the environment has been cleared and suppresses a further
self-execution. Alternatively, individual commands can be executed
with “pass:attributes[{blank}]`env -i`pass:attributes[{blank}]”.
[IMPORTANT]
====
Complete isolation from its original execution environment
(which is required when the script is executed after a trust
transition, e.g., triggered by the SUID mechanism) is impossible
to achieve from within the shell script itself. Instead, the
invoking process has to clear the process environment (except for
few trusted variables) before running the shell script.
====
Checking for failures in executed external commands is recommended.
If no elaborate error recovery is needed, invoking “pass:attributes[{blank}]`set
-e`pass:attributes[{blank}]” may be sufficient. This causes the script to stop on
the first failed command. However, failures in pipes
(“pass:attributes[{blank}]`command1 | command2`pass:attributes[{blank}]”) are only detected for the
last command in the pipe, errors in previous commands are ignored.
This can be changed by invoking “pass:attributes[{blank}]`set -o pipefail`pass:attributes[{blank}]”.
Due to architectural limitations, only the process that spawned
the entire pipe can check for failures in individual commands;
it is not possible for a process to tell if the process feeding
data (or the process consuming data) exited normally or with
an error.
See <<sect-Defensive_Coding-Tasks-Processes-Creation>>
for additional details on creating child processes.
[[sect-Defensive_Coding-Shell-Temporary_Files]]
== Temporary Files
Temporary files should be created with the
`mktemp` command, and temporary directories with
“pass:attributes[{blank}]`mktemp -d`pass:attributes[{blank}]”.
To clean up temporary files and directories, write a clean-up
shell function and register it as a trap handler, as shown in
<<ex-Defensive_Coding-Tasks-Temporary_Files>>.
Using a separate function avoids issues with proper quoting of
variables.
[[ex-Defensive_Coding-Tasks-Temporary_Files]]
.Creating and Cleaning up Temporary Files
====
[source,bash]
----
tmpfile="$(mktemp)"
cleanup () {
rm -f -- "$tmpfile"
}
trap cleanup 0
----
====
[[sect-Defensive_Coding-Shell-Input_Validation]]
== Performing Input Validation
In some cases, input validation cannot be avoided. For example,
if arithmetic evaluation is absolutely required, it is imperative
to check that input values are, in fact, integers. See <<sect-Defensive_Coding-Shell-Arithmetic>>.
<<ex-Defensive_Coding-Shell-Input_Validation>>
shows a construct which can be used to check if a string
“pass:attributes[{blank}]`$value`pass:attributes[{blank}]” is an integer. This construct is
specific to [application]*bash* and not portable to
POSIX shells.
[[ex-Defensive_Coding-Shell-Input_Validation]]
.Input validation in [application]*bash*
====
[source,bash]
----
include::../snippets/Shell-Input_Validation.adoc[]
----
====
Using `case` statements for input validation is
also possible and supported by other (POSIX) shells, but the
pattern language is more restrictive, and it can be difficult to
write suitable patterns.
The `expr` external command can give misleading
results (e.g., if the value being checked contains operators
itself) and should not be used.
[[sect-Defensive_Coding-Shell-Edit_Guard]]
== Guarding Shell Scripts Against Changes
[application]*bash* only reads a shell script up to
the point it is needed for executed the next command. This means
that if script is overwritten while it is running, execution can
jump to a random part of the script, depending on what is modified
in the script and how the file offsets change as a result. (This
behavior is needed to support self-extracting shell archives whose
script part is followed by a stream of bytes which does not follow
the shell language syntax.)
Therefore, long-running scripts should be guarded against
concurrent modification by putting as much of the program logic
into a `main` function, and invoking the
`main` function at the end of the script, using
this syntax:
[source,bash]
----
main "$@" ; exit $?
----
This construct ensures that [application]*bash* will
stop execution after the `main` function, instead
of opening the script file and trying to read more commands.

View file

@ -0,0 +1,36 @@
:experimental:
[[chap-Defensive_Coding-Vala]]
= The Vala Programming Language
Vala is a programming language mainly targeted at GNOME developers.
Its syntax is inspired by C# (and thus, indirectly, by Java). But
unlike C# and Java, Vala does not attempt to provide memory safety:
Vala is compiled to C, and the C code is compiled with GCC using
typical compiler flags. Basic operations like integer arithmetic
are directly mapped to C constructs. As a results, the
recommendations in <<chap-Defensive_Coding-C>> apply.
In particular, the following Vala language constructs can result in
undefined behavior at run time:
* Integer arithmetic, as described in <<sect-Defensive_Coding-C-Arithmetic>>.
* Pointer arithmetic, string subscripting and the
`substring` method on strings (the
`string` class in the
`glib-2.0` package) are not range-checked. It
is the responsibility of the calling code to ensure that the
arguments being passed are valid. This applies even to cases
(like `substring`) where the implementation
would have range information to check the validity of indexes.
See <<sect-Defensive_Coding-C-Pointers>>.
* Similarly, Vala only performs garbage collection (through
reference counting) for `GObject` values. For
plain C pointers (such as strings), the programmer has to ensure
that storage is deallocated once it is no longer needed (to
avoid memory leaks), and that storage is not being deallocated
while it is still being used (see <<sect-Defensive_Coding-C-Use-After-Free>>).

Some files were not shown because too many files have changed in this diff Show more