xref: /aoo41x/ext_libraries/serf/NULbytes.patch (revision 5661f8d9)
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