Git-Url: http://git.frugalware.org/gitweb/gitweb.cgi?p=frugalware-1.9.git;a=commitdiff;h=d59211b8db2bc73b7652202a654e2a81ae6f62a8
commit d59211b8db2bc73b7652202a654e2a81ae6f62a8 Author: kikadf <[email protected]> Date: Wed Aug 20 16:22:25 2014 +0200 serf-1.2.1-2arcturus1-x86_64 * Fix CVE-2014-3504 diff --git a/source/lib-extra/serf/CVE-2014-3504.patch b/source/lib-extra/serf/CVE-2014-3504.patch new file mode 100644 index 0000000..d684ffb --- /dev/null +++ b/source/lib-extra/serf/CVE-2014-3504.patch @@ -0,0 +1,287 @@ +Description: fix cert spoofing via NUL characters in CommonName and SubjectAltNames +Origin: upstream, https://code.google.com/p/serf/source/detail?r=2393 +Origin: upstream, https://code.google.com/p/serf/source/detail?r=2399 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=757965 + +Index: serf-1.3.3/buckets/ssl_buckets.c +=================================================================== +--- serf-1.3.3.orig/buckets/ssl_buckets.c 2013-11-29 16:22:42.000000000 -0500 ++++ serf-1.3.3/buckets/ssl_buckets.c 2014-08-14 09:47:21.047562793 -0400 +@@ -202,6 +202,8 @@ + }; + + static void disable_compression(serf_ssl_context_t *ssl_ctx); ++static char * ++ pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool); + + #if SSL_VERBOSE + /* Log all ssl alerts that we receive from the server. */ +@@ -427,6 +429,85 @@ + #endif + }; + ++typedef enum san_copy_t { ++ EscapeNulAndCopy = 0, ++ ErrorOnNul = 1, ++} san_copy_t; ++ ++ ++static apr_status_t ++get_subject_alt_names(apr_array_header_t **san_arr, X509 *ssl_cert, ++ san_copy_t copy_action, apr_pool_t *pool) ++{ ++ STACK_OF(GENERAL_NAME) *names; ++ ++ /* assert: copy_action == ErrorOnNul || (san_arr && pool) */ ++ ++ if (san_arr) { ++ *san_arr = NULL; ++ } ++ ++ /* Get subjectAltNames */ ++ names = X509_get_ext_d2i(ssl_cert, NID_subject_alt_name, NULL, NULL); ++ if (names) { ++ int names_count = sk_GENERAL_NAME_num(names); ++ int name_idx; ++ ++ if (san_arr) ++ *san_arr = apr_array_make(pool, names_count, sizeof(char*)); ++ for (name_idx = 0; name_idx < names_count; name_idx++) { ++ char *p = NULL; ++ GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, name_idx); ++ ++ switch (nm->type) { ++ case GEN_DNS: ++ if (copy_action == ErrorOnNul && ++ strlen(nm->d.ia5->data) != nm->d.ia5->length) ++ return SERF_ERROR_SSL_CERT_FAILED; ++ if (san_arr && *san_arr) ++ p = pstrdup_escape_nul_bytes((const char *)nm->d.ia5->data, ++ nm->d.ia5->length, ++ pool); ++ break; ++ default: ++ /* Don't know what to do - skip. */ ++ break; ++ } ++ ++ if (p) { ++ APR_ARRAY_PUSH(*san_arr, char*) = p; ++ } ++ } ++ sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); ++ } ++ ++ return APR_SUCCESS; ++} ++ ++static apr_status_t validate_cert_hostname(X509 *server_cert, apr_pool_t *pool) ++{ ++ char buf[1024]; ++ int length; ++ apr_status_t ret; ++ ++ ret = get_subject_alt_names(NULL, server_cert, ErrorOnNul, NULL); ++ if (ret) { ++ return ret; ++ } else { ++ /* Fail if the subject's CN field contains \0 characters. */ ++ X509_NAME *subject = X509_get_subject_name(server_cert); ++ if (!subject) ++ return SERF_ERROR_SSL_CERT_FAILED; ++ ++ length = X509_NAME_get_text_by_NID(subject, NID_commonName, buf, 1024); ++ if (length != -1) ++ if (strlen(buf) != length) ++ return SERF_ERROR_SSL_CERT_FAILED; ++ } ++ ++ return APR_SUCCESS; ++} ++ + static int + validate_server_certificate(int cert_valid, X509_STORE_CTX *store_ctx) + { +@@ -435,6 +516,7 @@ + X509 *server_cert; + int err, depth; + int failures = 0; ++ apr_status_t status; + + ssl = X509_STORE_CTX_get_ex_data(store_ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); +@@ -475,6 +557,11 @@ + } + } + ++ /* Validate hostname */ ++ status = validate_cert_hostname(server_cert, ctx->pool); ++ if (status) ++ failures |= SERF_SSL_CERT_UNKNOWN_FAILURE; ++ + /* Check certificate expiry dates. */ + if (X509_cmp_current_time(X509_get_notBefore(server_cert)) >= 0) { + failures |= SERF_SSL_CERT_NOTYETVALID; +@@ -485,7 +572,6 @@ + + if (ctx->server_cert_callback && + (depth == 0 || failures)) { +- apr_status_t status; + serf_ssl_certificate_t *cert; + apr_pool_t *subpool; + +@@ -512,7 +598,6 @@ + + if (ctx->server_cert_chain_callback + && (depth == 0 || failures)) { +- apr_status_t status; + STACK_OF(X509) *chain; + const serf_ssl_certificate_t **certs; + int certs_len; +@@ -1440,7 +1525,50 @@ + + /* Functions to read a serf_ssl_certificate structure. */ + +-/* Creates a hash_table with keys (E, CN, OU, O, L, ST and C). */ ++/* Takes a counted length string and escapes any NUL bytes so that ++ * it can be used as a C string. NUL bytes are escaped as 3 characters ++ * "\00" (that's a literal backslash). ++ * The returned string is allocated in POOL. ++ */ ++static char * ++pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool) ++{ ++ int i, nul_count = 0; ++ char *ret; ++ ++ /* First determine if there are any nul bytes in the string. */ ++ for (i = 0; i < len; i++) { ++ if (buf[i] == '\0') ++ nul_count++; ++ } ++ ++ if (nul_count == 0) { ++ /* There aren't so easy case to just copy the string */ ++ ret = apr_pstrdup(pool, buf); ++ } else { ++ /* There are so we have to replace nul bytes with escape codes ++ * Proper length is the length of the original string, plus ++ * 2 times the number of nulls (for two digit hex code for ++ * the value) + the trailing null. */ ++ char *pos; ++ ret = pos = apr_palloc(pool, len + 2 * nul_count + 1); ++ for (i = 0; i < len; i++) { ++ if (buf[i] != '\0') { ++ *(pos++) = buf[i]; ++ } else { ++ *(pos++) = '\\'; ++ *(pos++) = '0'; ++ *(pos++) = '0'; ++ } ++ } ++ *pos = '\0'; ++ } ++ ++ return ret; ++} ++ ++/* Creates a hash_table with keys (E, CN, OU, O, L, ST and C). Any NUL bytes in ++ these fields in the certificate will be escaped as \00. */ + static apr_hash_t * + convert_X509_NAME_to_table(X509_NAME *org, apr_pool_t *pool) + { +@@ -1453,37 +1581,44 @@ + NID_commonName, + buf, 1024); + if (ret != -1) +- apr_hash_set(tgt, "CN", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); ++ apr_hash_set(tgt, "CN", APR_HASH_KEY_STRING, ++ pstrdup_escape_nul_bytes(buf, ret, pool)); + ret = X509_NAME_get_text_by_NID(org, + NID_pkcs9_emailAddress, + buf, 1024); + if (ret != -1) +- apr_hash_set(tgt, "E", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); ++ apr_hash_set(tgt, "E", APR_HASH_KEY_STRING, ++ pstrdup_escape_nul_bytes(buf, ret, pool)); + ret = X509_NAME_get_text_by_NID(org, + NID_organizationalUnitName, + buf, 1024); + if (ret != -1) +- apr_hash_set(tgt, "OU", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); ++ apr_hash_set(tgt, "OU", APR_HASH_KEY_STRING, ++ pstrdup_escape_nul_bytes(buf, ret, pool)); + ret = X509_NAME_get_text_by_NID(org, + NID_organizationName, + buf, 1024); + if (ret != -1) +- apr_hash_set(tgt, "O", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); ++ apr_hash_set(tgt, "O", APR_HASH_KEY_STRING, ++ pstrdup_escape_nul_bytes(buf, ret, pool)); + ret = X509_NAME_get_text_by_NID(org, + NID_localityName, + buf, 1024); + if (ret != -1) +- apr_hash_set(tgt, "L", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); ++ apr_hash_set(tgt, "L", APR_HASH_KEY_STRING, ++ pstrdup_escape_nul_bytes(buf, ret, pool)); + ret = X509_NAME_get_text_by_NID(org, + NID_stateOrProvinceName, + buf, 1024); + if (ret != -1) +- apr_hash_set(tgt, "ST", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); ++ apr_hash_set(tgt, "ST", APR_HASH_KEY_STRING, ++ pstrdup_escape_nul_bytes(buf, ret, pool)); + ret = X509_NAME_get_text_by_NID(org, + NID_countryName, + buf, 1024); + if (ret != -1) +- apr_hash_set(tgt, "C", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); ++ apr_hash_set(tgt, "C", APR_HASH_KEY_STRING, ++ pstrdup_escape_nul_bytes(buf, ret, pool)); + + return tgt; + } +@@ -1529,7 +1664,7 @@ + unsigned int md_size, i; + unsigned char md[EVP_MAX_MD_SIZE]; + BIO *bio; +- STACK_OF(GENERAL_NAME) *names; ++ apr_array_header_t *san_arr; + + /* sha1 fingerprint */ + if (X509_digest(cert->ssl_cert, EVP_sha1(), md, &md_size)) { +@@ -1574,32 +1709,8 @@ + BIO_free(bio); + + /* Get subjectAltNames */ +- names = X509_get_ext_d2i(cert->ssl_cert, NID_subject_alt_name, NULL, NULL); +- if (names) { +- int names_count = sk_GENERAL_NAME_num(names); +- +- apr_array_header_t *san_arr = apr_array_make(pool, names_count, +- sizeof(char*)); ++ if (!get_subject_alt_names(&san_arr, cert->ssl_cert, EscapeNulAndCopy, pool)) + apr_hash_set(tgt, "subjectAltName", APR_HASH_KEY_STRING, san_arr); +- for (i = 0; i < names_count; i++) { +- char *p = NULL; +- GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, i); +- +- switch (nm->type) { +- case GEN_DNS: +- p = apr_pstrmemdup(pool, (const char *)nm->d.ia5->data, +- nm->d.ia5->length); +- break; +- default: +- /* Don't know what to do - skip. */ +- break; +- } +- if (p) { +- APR_ARRAY_PUSH(san_arr, char*) = p; +- } +- } +- sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); +- } + + return tgt; + } diff --git a/source/lib-extra/serf/FrugalBuild b/source/lib-extra/serf/FrugalBuild index 932e670..0bca21a 100644 --- a/source/lib-extra/serf/FrugalBuild +++ b/source/lib-extra/serf/FrugalBuild @@ -3,7 +3,7 @@ pkgname=serf pkgver=1.2.1 -pkgrel=1 +pkgrel=2arcturus1 pkgdesc="High-performance asynchronous HTTP client library" archs=('i686' 'x86_64') groups=('lib-extra') @@ -12,4 +12,9 @@ sha1sums=('f65fbbd72926c8e7cf0dbd4ada03b0d226f461fd') _F_googlecode_ext=".tar.bz2" Finclude googlecode +# FSA fix *** +source=(${source[@]} CVE-2014-3504.patch) +sha1sums=(${sha1sums[@]} 'a53de5b34e1a7812cb7e3d422aef0edddd90145c') +# *********** + # optimization OK _______________________________________________ Frugalware-git mailing list [email protected] http://frugalware.org/mailman/listinfo/frugalware-git
