1*5661f8d9SDon Lewis------------------------------------------------------------------------ 2*5661f8d9SDon Lewisr1699925 | breser | 2014-08-04 11:04:00 -0700 (Mon, 04 Aug 2014) | 5 lines 3*5661f8d9SDon Lewis 4*5661f8d9SDon LewisOn the 1.3.x branch: 5*5661f8d9SDon Lewis 6*5661f8d9SDon LewisMerge changes from trunk: 7*5661f8d9SDon Lewis- r2392: Handle NUL bytes in fields of X.509 certs. 8*5661f8d9SDon Lewis 9*5661f8d9SDon Lewis------------------------------------------------------------------------ 10*5661f8d9SDon LewisIndex: misc/build/serf-1.2.1/buckets/ssl_buckets.c 11*5661f8d9SDon Lewis=================================================================== 12*5661f8d9SDon Lewis--- misc/serf-1.2.1/buckets/ssl_buckets.c (revision 1699924) 13*5661f8d9SDon Lewis+++ misc/build/serf-1.2.1/buckets/ssl_buckets.c (revision 1699925) 14*5661f8d9SDon Lewis@@ -202,6 +202,8 @@ 15*5661f8d9SDon Lewis }; 16*5661f8d9SDon Lewis 17*5661f8d9SDon Lewis static void disable_compression(serf_ssl_context_t *ssl_ctx); 18*5661f8d9SDon Lewis+static char * 19*5661f8d9SDon Lewis+ pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool); 20*5661f8d9SDon Lewis 21*5661f8d9SDon Lewis #if SSL_VERBOSE 22*5661f8d9SDon Lewis /* Log all ssl alerts that we receive from the server. */ 23*5661f8d9SDon Lewis@@ -427,6 +429,81 @@ 24*5661f8d9SDon Lewis #endif 25*5661f8d9SDon Lewis }; 26*5661f8d9SDon Lewis 27*5661f8d9SDon Lewis+typedef enum san_copy_t { 28*5661f8d9SDon Lewis+ EscapeNulAndCopy = 0, 29*5661f8d9SDon Lewis+ ErrorOnNul = 1, 30*5661f8d9SDon Lewis+} san_copy_t; 31*5661f8d9SDon Lewis+ 32*5661f8d9SDon Lewis+ 33*5661f8d9SDon Lewis+static apr_status_t 34*5661f8d9SDon Lewis+get_subject_alt_names(apr_array_header_t **san_arr, X509 *ssl_cert, 35*5661f8d9SDon Lewis+ san_copy_t copy_action, apr_pool_t *pool) 36*5661f8d9SDon Lewis+{ 37*5661f8d9SDon Lewis+ STACK_OF(GENERAL_NAME) *names; 38*5661f8d9SDon Lewis+ 39*5661f8d9SDon Lewis+ /* assert: copy_action == ErrorOnNul || (san_arr && pool) */ 40*5661f8d9SDon Lewis+ 41*5661f8d9SDon Lewis+ /* Get subjectAltNames */ 42*5661f8d9SDon Lewis+ names = X509_get_ext_d2i(ssl_cert, NID_subject_alt_name, NULL, NULL); 43*5661f8d9SDon Lewis+ if (names) { 44*5661f8d9SDon Lewis+ int names_count = sk_GENERAL_NAME_num(names); 45*5661f8d9SDon Lewis+ int name_idx; 46*5661f8d9SDon Lewis+ 47*5661f8d9SDon Lewis+ if (san_arr) 48*5661f8d9SDon Lewis+ *san_arr = apr_array_make(pool, names_count, sizeof(char*)); 49*5661f8d9SDon Lewis+ for (name_idx = 0; name_idx < names_count; name_idx++) { 50*5661f8d9SDon Lewis+ char *p = NULL; 51*5661f8d9SDon Lewis+ GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, name_idx); 52*5661f8d9SDon Lewis+ 53*5661f8d9SDon Lewis+ switch (nm->type) { 54*5661f8d9SDon Lewis+ case GEN_DNS: 55*5661f8d9SDon Lewis+ if (copy_action == ErrorOnNul && 56*5661f8d9SDon Lewis+ strlen(nm->d.ia5->data) != nm->d.ia5->length) 57*5661f8d9SDon Lewis+ return SERF_ERROR_SSL_CERT_FAILED; 58*5661f8d9SDon Lewis+ if (san_arr && *san_arr) 59*5661f8d9SDon Lewis+ p = pstrdup_escape_nul_bytes((const char *)nm->d.ia5->data, 60*5661f8d9SDon Lewis+ nm->d.ia5->length, 61*5661f8d9SDon Lewis+ pool); 62*5661f8d9SDon Lewis+ break; 63*5661f8d9SDon Lewis+ default: 64*5661f8d9SDon Lewis+ /* Don't know what to do - skip. */ 65*5661f8d9SDon Lewis+ break; 66*5661f8d9SDon Lewis+ } 67*5661f8d9SDon Lewis+ 68*5661f8d9SDon Lewis+ if (p) { 69*5661f8d9SDon Lewis+ APR_ARRAY_PUSH(*san_arr, char*) = p; 70*5661f8d9SDon Lewis+ } 71*5661f8d9SDon Lewis+ } 72*5661f8d9SDon Lewis+ sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); 73*5661f8d9SDon Lewis+ } 74*5661f8d9SDon Lewis+ 75*5661f8d9SDon Lewis+ return APR_SUCCESS; 76*5661f8d9SDon Lewis+} 77*5661f8d9SDon Lewis+ 78*5661f8d9SDon Lewis+static apr_status_t validate_cert_hostname(X509 *server_cert, apr_pool_t *pool) 79*5661f8d9SDon Lewis+{ 80*5661f8d9SDon Lewis+ char buf[1024]; 81*5661f8d9SDon Lewis+ int length; 82*5661f8d9SDon Lewis+ apr_status_t ret; 83*5661f8d9SDon Lewis+ 84*5661f8d9SDon Lewis+ ret = get_subject_alt_names(NULL, server_cert, ErrorOnNul, NULL); 85*5661f8d9SDon Lewis+ if (ret) { 86*5661f8d9SDon Lewis+ return ret; 87*5661f8d9SDon Lewis+ } else { 88*5661f8d9SDon Lewis+ /* Fail if the subject's CN field contains \0 characters. */ 89*5661f8d9SDon Lewis+ X509_NAME *subject = X509_get_subject_name(server_cert); 90*5661f8d9SDon Lewis+ if (!subject) 91*5661f8d9SDon Lewis+ return SERF_ERROR_SSL_CERT_FAILED; 92*5661f8d9SDon Lewis+ 93*5661f8d9SDon Lewis+ length = X509_NAME_get_text_by_NID(subject, NID_commonName, buf, 1024); 94*5661f8d9SDon Lewis+ if (length != -1) 95*5661f8d9SDon Lewis+ if (strlen(buf) != length) 96*5661f8d9SDon Lewis+ return SERF_ERROR_SSL_CERT_FAILED; 97*5661f8d9SDon Lewis+ } 98*5661f8d9SDon Lewis+ 99*5661f8d9SDon Lewis+ return APR_SUCCESS; 100*5661f8d9SDon Lewis+} 101*5661f8d9SDon Lewis+ 102*5661f8d9SDon Lewis static int 103*5661f8d9SDon Lewis validate_server_certificate(int cert_valid, X509_STORE_CTX *store_ctx) 104*5661f8d9SDon Lewis { 105*5661f8d9SDon Lewis@@ -435,6 +512,7 @@ 106*5661f8d9SDon Lewis X509 *server_cert; 107*5661f8d9SDon Lewis int err, depth; 108*5661f8d9SDon Lewis int failures = 0; 109*5661f8d9SDon Lewis+ apr_status_t status; 110*5661f8d9SDon Lewis 111*5661f8d9SDon Lewis ssl = X509_STORE_CTX_get_ex_data(store_ctx, 112*5661f8d9SDon Lewis SSL_get_ex_data_X509_STORE_CTX_idx()); 113*5661f8d9SDon Lewis@@ -475,6 +553,11 @@ 114*5661f8d9SDon Lewis } 115*5661f8d9SDon Lewis } 116*5661f8d9SDon Lewis 117*5661f8d9SDon Lewis+ /* Validate hostname */ 118*5661f8d9SDon Lewis+ status = validate_cert_hostname(server_cert, ctx->pool); 119*5661f8d9SDon Lewis+ if (status) 120*5661f8d9SDon Lewis+ failures |= SERF_SSL_CERT_UNKNOWN_FAILURE; 121*5661f8d9SDon Lewis+ 122*5661f8d9SDon Lewis /* Check certificate expiry dates. */ 123*5661f8d9SDon Lewis if (X509_cmp_current_time(X509_get_notBefore(server_cert)) >= 0) { 124*5661f8d9SDon Lewis failures |= SERF_SSL_CERT_NOTYETVALID; 125*5661f8d9SDon Lewis@@ -485,7 +568,6 @@ 126*5661f8d9SDon Lewis 127*5661f8d9SDon Lewis if (ctx->server_cert_callback && 128*5661f8d9SDon Lewis (depth == 0 || failures)) { 129*5661f8d9SDon Lewis- apr_status_t status; 130*5661f8d9SDon Lewis serf_ssl_certificate_t *cert; 131*5661f8d9SDon Lewis apr_pool_t *subpool; 132*5661f8d9SDon Lewis 133*5661f8d9SDon Lewis@@ -512,7 +594,6 @@ 134*5661f8d9SDon Lewis 135*5661f8d9SDon Lewis if (ctx->server_cert_chain_callback 136*5661f8d9SDon Lewis && (depth == 0 || failures)) { 137*5661f8d9SDon Lewis- apr_status_t status; 138*5661f8d9SDon Lewis STACK_OF(X509) *chain; 139*5661f8d9SDon Lewis const serf_ssl_certificate_t **certs; 140*5661f8d9SDon Lewis int certs_len; 141*5661f8d9SDon Lewis@@ -1461,7 +1542,50 @@ 142*5661f8d9SDon Lewis 143*5661f8d9SDon Lewis /* Functions to read a serf_ssl_certificate structure. */ 144*5661f8d9SDon Lewis 145*5661f8d9SDon Lewis-/* Creates a hash_table with keys (E, CN, OU, O, L, ST and C). */ 146*5661f8d9SDon Lewis+/* Takes a counted length string and escapes any NUL bytes so that 147*5661f8d9SDon Lewis+ * it can be used as a C string. NUL bytes are escaped as 3 characters 148*5661f8d9SDon Lewis+ * "\00" (that's a literal backslash). 149*5661f8d9SDon Lewis+ * The returned string is allocated in POOL. 150*5661f8d9SDon Lewis+ */ 151*5661f8d9SDon Lewis+static char * 152*5661f8d9SDon Lewis+pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool) 153*5661f8d9SDon Lewis+{ 154*5661f8d9SDon Lewis+ int i, nul_count = 0; 155*5661f8d9SDon Lewis+ char *ret; 156*5661f8d9SDon Lewis+ 157*5661f8d9SDon Lewis+ /* First determine if there are any nul bytes in the string. */ 158*5661f8d9SDon Lewis+ for (i = 0; i < len; i++) { 159*5661f8d9SDon Lewis+ if (buf[i] == '\0') 160*5661f8d9SDon Lewis+ nul_count++; 161*5661f8d9SDon Lewis+ } 162*5661f8d9SDon Lewis+ 163*5661f8d9SDon Lewis+ if (nul_count == 0) { 164*5661f8d9SDon Lewis+ /* There aren't so easy case to just copy the string */ 165*5661f8d9SDon Lewis+ ret = apr_pstrdup(pool, buf); 166*5661f8d9SDon Lewis+ } else { 167*5661f8d9SDon Lewis+ /* There are so we have to replace nul bytes with escape codes 168*5661f8d9SDon Lewis+ * Proper length is the length of the original string, plus 169*5661f8d9SDon Lewis+ * 2 times the number of nulls (for two digit hex code for 170*5661f8d9SDon Lewis+ * the value) + the trailing null. */ 171*5661f8d9SDon Lewis+ char *pos; 172*5661f8d9SDon Lewis+ ret = pos = apr_palloc(pool, len + 2 * nul_count + 1); 173*5661f8d9SDon Lewis+ for (i = 0; i < len; i++) { 174*5661f8d9SDon Lewis+ if (buf[i] != '\0') { 175*5661f8d9SDon Lewis+ *(pos++) = buf[i]; 176*5661f8d9SDon Lewis+ } else { 177*5661f8d9SDon Lewis+ *(pos++) = '\\'; 178*5661f8d9SDon Lewis+ *(pos++) = '0'; 179*5661f8d9SDon Lewis+ *(pos++) = '0'; 180*5661f8d9SDon Lewis+ } 181*5661f8d9SDon Lewis+ } 182*5661f8d9SDon Lewis+ *pos = '\0'; 183*5661f8d9SDon Lewis+ } 184*5661f8d9SDon Lewis+ 185*5661f8d9SDon Lewis+ return ret; 186*5661f8d9SDon Lewis+} 187*5661f8d9SDon Lewis+ 188*5661f8d9SDon Lewis+/* Creates a hash_table with keys (E, CN, OU, O, L, ST and C). Any NUL bytes in 189*5661f8d9SDon Lewis+ these fields in the certificate will be escaped as \00. */ 190*5661f8d9SDon Lewis static apr_hash_t * 191*5661f8d9SDon Lewis convert_X509_NAME_to_table(X509_NAME *org, apr_pool_t *pool) 192*5661f8d9SDon Lewis { 193*5661f8d9SDon Lewis@@ -1474,37 +1598,44 @@ 194*5661f8d9SDon Lewis NID_commonName, 195*5661f8d9SDon Lewis buf, 1024); 196*5661f8d9SDon Lewis if (ret != -1) 197*5661f8d9SDon Lewis- apr_hash_set(tgt, "CN", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); 198*5661f8d9SDon Lewis+ apr_hash_set(tgt, "CN", APR_HASH_KEY_STRING, 199*5661f8d9SDon Lewis+ pstrdup_escape_nul_bytes(buf, ret, pool)); 200*5661f8d9SDon Lewis ret = X509_NAME_get_text_by_NID(org, 201*5661f8d9SDon Lewis NID_pkcs9_emailAddress, 202*5661f8d9SDon Lewis buf, 1024); 203*5661f8d9SDon Lewis if (ret != -1) 204*5661f8d9SDon Lewis- apr_hash_set(tgt, "E", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); 205*5661f8d9SDon Lewis+ apr_hash_set(tgt, "E", APR_HASH_KEY_STRING, 206*5661f8d9SDon Lewis+ pstrdup_escape_nul_bytes(buf, ret, pool)); 207*5661f8d9SDon Lewis ret = X509_NAME_get_text_by_NID(org, 208*5661f8d9SDon Lewis NID_organizationalUnitName, 209*5661f8d9SDon Lewis buf, 1024); 210*5661f8d9SDon Lewis if (ret != -1) 211*5661f8d9SDon Lewis- apr_hash_set(tgt, "OU", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); 212*5661f8d9SDon Lewis+ apr_hash_set(tgt, "OU", APR_HASH_KEY_STRING, 213*5661f8d9SDon Lewis+ pstrdup_escape_nul_bytes(buf, ret, pool)); 214*5661f8d9SDon Lewis ret = X509_NAME_get_text_by_NID(org, 215*5661f8d9SDon Lewis NID_organizationName, 216*5661f8d9SDon Lewis buf, 1024); 217*5661f8d9SDon Lewis if (ret != -1) 218*5661f8d9SDon Lewis- apr_hash_set(tgt, "O", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); 219*5661f8d9SDon Lewis+ apr_hash_set(tgt, "O", APR_HASH_KEY_STRING, 220*5661f8d9SDon Lewis+ pstrdup_escape_nul_bytes(buf, ret, pool)); 221*5661f8d9SDon Lewis ret = X509_NAME_get_text_by_NID(org, 222*5661f8d9SDon Lewis NID_localityName, 223*5661f8d9SDon Lewis buf, 1024); 224*5661f8d9SDon Lewis if (ret != -1) 225*5661f8d9SDon Lewis- apr_hash_set(tgt, "L", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); 226*5661f8d9SDon Lewis+ apr_hash_set(tgt, "L", APR_HASH_KEY_STRING, 227*5661f8d9SDon Lewis+ pstrdup_escape_nul_bytes(buf, ret, pool)); 228*5661f8d9SDon Lewis ret = X509_NAME_get_text_by_NID(org, 229*5661f8d9SDon Lewis NID_stateOrProvinceName, 230*5661f8d9SDon Lewis buf, 1024); 231*5661f8d9SDon Lewis if (ret != -1) 232*5661f8d9SDon Lewis- apr_hash_set(tgt, "ST", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); 233*5661f8d9SDon Lewis+ apr_hash_set(tgt, "ST", APR_HASH_KEY_STRING, 234*5661f8d9SDon Lewis+ pstrdup_escape_nul_bytes(buf, ret, pool)); 235*5661f8d9SDon Lewis ret = X509_NAME_get_text_by_NID(org, 236*5661f8d9SDon Lewis NID_countryName, 237*5661f8d9SDon Lewis buf, 1024); 238*5661f8d9SDon Lewis if (ret != -1) 239*5661f8d9SDon Lewis- apr_hash_set(tgt, "C", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); 240*5661f8d9SDon Lewis+ apr_hash_set(tgt, "C", APR_HASH_KEY_STRING, 241*5661f8d9SDon Lewis+ pstrdup_escape_nul_bytes(buf, ret, pool)); 242*5661f8d9SDon Lewis 243*5661f8d9SDon Lewis return tgt; 244*5661f8d9SDon Lewis } 245*5661f8d9SDon Lewis@@ -1550,7 +1681,7 @@ 246*5661f8d9SDon Lewis unsigned int md_size, i; 247*5661f8d9SDon Lewis unsigned char md[EVP_MAX_MD_SIZE]; 248*5661f8d9SDon Lewis BIO *bio; 249*5661f8d9SDon Lewis- STACK_OF(GENERAL_NAME) *names; 250*5661f8d9SDon Lewis+ apr_array_header_t *san_arr; 251*5661f8d9SDon Lewis 252*5661f8d9SDon Lewis /* sha1 fingerprint */ 253*5661f8d9SDon Lewis if (X509_digest(cert->ssl_cert, EVP_sha1(), md, &md_size)) { 254*5661f8d9SDon Lewis@@ -1595,33 +1726,9 @@ 255*5661f8d9SDon Lewis BIO_free(bio); 256*5661f8d9SDon Lewis 257*5661f8d9SDon Lewis /* Get subjectAltNames */ 258*5661f8d9SDon Lewis- names = X509_get_ext_d2i(cert->ssl_cert, NID_subject_alt_name, NULL, NULL); 259*5661f8d9SDon Lewis- if (names) { 260*5661f8d9SDon Lewis- int names_count = sk_GENERAL_NAME_num(names); 261*5661f8d9SDon Lewis- 262*5661f8d9SDon Lewis- apr_array_header_t *san_arr = apr_array_make(pool, names_count, 263*5661f8d9SDon Lewis- sizeof(char*)); 264*5661f8d9SDon Lewis+ if (!get_subject_alt_names(&san_arr, cert->ssl_cert, EscapeNulAndCopy, pool)) 265*5661f8d9SDon Lewis apr_hash_set(tgt, "subjectAltName", APR_HASH_KEY_STRING, san_arr); 266*5661f8d9SDon Lewis- for (i = 0; i < names_count; i++) { 267*5661f8d9SDon Lewis- char *p = NULL; 268*5661f8d9SDon Lewis- GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, i); 269*5661f8d9SDon Lewis 270*5661f8d9SDon Lewis- switch (nm->type) { 271*5661f8d9SDon Lewis- case GEN_DNS: 272*5661f8d9SDon Lewis- p = apr_pstrmemdup(pool, (const char *)nm->d.ia5->data, 273*5661f8d9SDon Lewis- nm->d.ia5->length); 274*5661f8d9SDon Lewis- break; 275*5661f8d9SDon Lewis- default: 276*5661f8d9SDon Lewis- /* Don't know what to do - skip. */ 277*5661f8d9SDon Lewis- break; 278*5661f8d9SDon Lewis- } 279*5661f8d9SDon Lewis- if (p) { 280*5661f8d9SDon Lewis- APR_ARRAY_PUSH(san_arr, char*) = p; 281*5661f8d9SDon Lewis- } 282*5661f8d9SDon Lewis- } 283*5661f8d9SDon Lewis- sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); 284*5661f8d9SDon Lewis- } 285*5661f8d9SDon Lewis- 286*5661f8d9SDon Lewis return tgt; 287*5661f8d9SDon Lewis } 288*5661f8d9SDon Lewis 289*5661f8d9SDon Lewis------------------------------------------------------------------------ 290*5661f8d9SDon Lewisr1699931 | breser | 2014-08-05 19:24:00 -0700 (Tue, 05 Aug 2014) | 6 lines 291*5661f8d9SDon Lewis 292*5661f8d9SDon LewisOn the 1.3.x branch: 293*5661f8d9SDon Lewis 294*5661f8d9SDon LewisMerge changes from trunk: 295*5661f8d9SDon Lewis- r2398: Initialize san_arr when we're expected to fill it. 296*5661f8d9SDon Lewis 297*5661f8d9SDon Lewis 298*5661f8d9SDon Lewis------------------------------------------------------------------------ 299*5661f8d9SDon LewisIndex: misc/build/serf-1.2.1/buckets/ssl_buckets.c 300*5661f8d9SDon Lewis=================================================================== 301*5661f8d9SDon Lewis--- misc/serf-1.2.1/buckets/ssl_buckets.c (revision 1699930) 302*5661f8d9SDon Lewis+++ misc/build/serf-1.2.1/buckets/ssl_buckets.c (revision 1699931) 303*5661f8d9SDon Lewis@@ -443,6 +443,10 @@ 304*5661f8d9SDon Lewis 305*5661f8d9SDon Lewis /* assert: copy_action == ErrorOnNul || (san_arr && pool) */ 306*5661f8d9SDon Lewis 307*5661f8d9SDon Lewis+ if (san_arr) { 308*5661f8d9SDon Lewis+ *san_arr = NULL; 309*5661f8d9SDon Lewis+ } 310*5661f8d9SDon Lewis+ 311*5661f8d9SDon Lewis /* Get subjectAltNames */ 312*5661f8d9SDon Lewis names = X509_get_ext_d2i(ssl_cert, NID_subject_alt_name, NULL, NULL); 313*5661f8d9SDon Lewis if (names) { 314