Merge ~j-latten/ubuntu/+source/openvpn:xenial-openvpn-fips-crash-1807439 into ubuntu/+source/openvpn:ubuntu/xenial-devel

Proposed by Joy Latten
Status: Merged
Approved by: Andreas Hasenack
Approved revision: 8c4584bd5ceeb65241566e00049c7be88166646f
Merged at revision: 8c4584bd5ceeb65241566e00049c7be88166646f
Proposed branch: ~j-latten/ubuntu/+source/openvpn:xenial-openvpn-fips-crash-1807439
Merge into: ubuntu/+source/openvpn:ubuntu/xenial-devel
Diff against target: 373 lines (+351/-0)
3 files modified
debian/changelog (+7/-0)
debian/patches/openvpn-fips140-2.3.2.patch (+343/-0)
debian/patches/series (+1/-0)
Reviewer Review Type Date Requested Status
Andreas Hasenack Approve
Seth Arnold (community) Approve
Review via email: mp+361638@code.launchpad.net

Description of the change

openvpn segfaults when linked with fips-mode openssl because of MD5 algo.

openvpn version 2.3.x uses MD5 for (1). hashing its internal state and (2) tls connection TLS PRF(pseudorandom function).

FIPS 140-2 does not permit MD5 except for PRF. fips mode openssl checks a flag value to permit this.

Upstream, openvpn 2.4.x internal hash algo was changed to SHA256, thus fixing (1) in 2.4.x. Thus this fix for version 2.3.x changes algo to SHA256.

For (2), openvpn needs to set a context flag-value that FIPS-mode libcrypto.so checks to indicate permit MD5. FIPS-mode libcrypto.so will grant the request instead of entering an error state. In non-FIPS libcrypto.so this check does not exist since it always permits MD5. However, the particular flag value is defined in both fips and non-fips openssl code.

Note: Upstream has not fixed (2).

To post a comment you must log in.
Revision history for this message
Seth Arnold (seth-arnold) wrote :

Looks good to me, thanks.

review: Approve
Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Thanks, sponsoring.

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Tagged and uploaded.

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

and my +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index 0bfc355..5ae9970 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,10 @@
6+openvpn (2.3.10-1ubuntu2.2) xenial; urgency=medium
7+
8+ * d/p/openvpn-fips140-2.3.2.patch: Replace MD5 internal hash
9+ with SHA256 and allow MD5 for PRF. (LP: #1807439)
10+
11+ -- Joy Latten <joy.latten@canonical.com> Wed, 09 Jan 2019 16:31:45 -0600
12+
13 openvpn (2.3.10-1ubuntu2.1) xenial-security; urgency=medium
14
15 * SECURITY UPDATE: birthday attack when using 64-bit block cipher
16diff --git a/debian/patches/openvpn-fips140-2.3.2.patch b/debian/patches/openvpn-fips140-2.3.2.patch
17new file mode 100644
18index 0000000..c40484d
19--- /dev/null
20+++ b/debian/patches/openvpn-fips140-2.3.2.patch
21@@ -0,0 +1,343 @@
22+Description: Use FIPS algos in openvpn
23+ OpenVPN sends openssl requests to perform MD5 hash for (1) internal
24+ configuration status verification and (2) TLS PRF. FIPS 140-2 does
25+ not allow MD5 except for PRF. OpenVPN needs to use SHA for internal
26+ verification and send EVP_MD_CTX_FLAG_NON_FIPS_ALLOW flag to
27+ indicate PRF exception.
28+ Upstream has changed internal hash to SHA256 in more recent
29+ versions, but has delayed additional FIPS improvements.
30+Bug: https://community.openvpn.net/openvpn/ticket/725
31+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1807439
32+Author: Stephan Mueller <stephan.mueller@atsec.com>
33+
34+diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
35+index 7d9736b..f89b9aa 100644
36+--- a/src/openvpn/crypto.c
37++++ b/src/openvpn/crypto.c
38+@@ -506,7 +506,7 @@ init_key_ctx (struct key_ctx *ctx, struct key *key,
39+ if (kt->digest && kt->hmac_length > 0)
40+ {
41+ ALLOC_OBJ(ctx->hmac, hmac_ctx_t);
42+- hmac_ctx_init (ctx->hmac, key->hmac, kt->hmac_length, kt->digest);
43++ hmac_ctx_init (ctx->hmac, key->hmac, kt->hmac_length, kt->digest, 0);
44+
45+ msg (D_HANDSHAKE,
46+ "%s: Using %d bit message hash '%s' for HMAC authentication",
47+@@ -1422,61 +1422,62 @@ free_ssl_lib (void)
48+ #endif /* ENABLE_SSL */
49+
50+ /*
51+- * md5 functions
52++ * sha256 functions
53+ */
54+
55+ const char *
56+-md5sum (uint8_t *buf, int len, int n_print_chars, struct gc_arena *gc)
57++sha256sum (uint8_t *buf, int len, int n_print_chars, struct gc_arena *gc)
58+ {
59+- uint8_t digest[MD5_DIGEST_LENGTH];
60+- const md_kt_t *md5_kt = md_kt_get("MD5");
61++ uint8_t digest[SHA256_DIGEST_LENGTH];
62++ const md_kt_t *sha256_kt = md_kt_get("SHA256");
63+
64+- md_full(md5_kt, buf, len, digest);
65++ md_full(sha256_kt, buf, len, digest);
66+
67+- return format_hex (digest, MD5_DIGEST_LENGTH, n_print_chars, gc);
68++ return format_hex (digest, SHA256_DIGEST_LENGTH, n_print_chars, gc);
69+ }
70+
71+ void
72+-md5_state_init (struct md5_state *s)
73++sha256_state_init (struct sha256_state *s)
74+ {
75+- const md_kt_t *md5_kt = md_kt_get("MD5");
76++ const md_kt_t *sha256_kt = md_kt_get("SHA256");
77+
78+- md_ctx_init(&s->ctx, md5_kt);
79++ md_ctx_init(&s->ctx, sha256_kt);
80+ }
81+
82+ void
83+-md5_state_update (struct md5_state *s, void *data, size_t len)
84++sha256_state_update (struct sha256_state *s, void *data, size_t len)
85+ {
86+ md_ctx_update(&s->ctx, data, len);
87+ }
88+
89+ void
90+-md5_state_final (struct md5_state *s, struct md5_digest *out)
91++sha256_state_final (struct sha256_state *s, struct sha256_digest *out)
92+ {
93+ md_ctx_final(&s->ctx, out->digest);
94+ md_ctx_cleanup(&s->ctx);
95+ }
96+
97+ void
98+-md5_digest_clear (struct md5_digest *digest)
99++sha256_digest_clear (struct sha256_digest *digest)
100+ {
101+ CLEAR (*digest);
102+ }
103+
104+ bool
105+-md5_digest_defined (const struct md5_digest *digest)
106++sha256_digest_defined (const struct sha256_digest *digest)
107+ {
108+ int i;
109+- for (i = 0; i < MD5_DIGEST_LENGTH; ++i)
110++ for (i = 0; i < SHA256_DIGEST_LENGTH; ++i)
111+ if (digest->digest[i])
112+ return true;
113+ return false;
114+ }
115+
116+ bool
117+-md5_digest_equal (const struct md5_digest *d1, const struct md5_digest *d2)
118++sha256_digest_equal (const struct sha256_digest *d1,
119++ const struct sha256_digest *d2)
120+ {
121+- return memcmp(d1->digest, d2->digest, MD5_DIGEST_LENGTH) == 0;
122++ return memcmp(d1->digest, d2->digest, SHA256_DIGEST_LENGTH) == 0;
123+ }
124+
125+ #endif /* ENABLE_CRYPTO */
126+diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
127+index e489827..9f991cc 100644
128+--- a/src/openvpn/crypto.h
129++++ b/src/openvpn/crypto.h
130+@@ -430,24 +430,24 @@ void free_ssl_lib (void);
131+ #endif /* ENABLE_SSL */
132+
133+ /*
134+- * md5 functions
135++ * sha256 functions
136+ */
137+
138+-struct md5_state {
139++struct sha256_state {
140+ md_ctx_t ctx;
141+ };
142+
143+-struct md5_digest {
144+- uint8_t digest [MD5_DIGEST_LENGTH];
145++struct sha256_digest {
146++ uint8_t digest [SHA256_DIGEST_LENGTH];
147+ };
148+
149+-const char *md5sum(uint8_t *buf, int len, int n_print_chars, struct gc_arena *gc);
150+-void md5_state_init (struct md5_state *s);
151+-void md5_state_update (struct md5_state *s, void *data, size_t len);
152+-void md5_state_final (struct md5_state *s, struct md5_digest *out);
153+-void md5_digest_clear (struct md5_digest *digest);
154+-bool md5_digest_defined (const struct md5_digest *digest);
155+-bool md5_digest_equal (const struct md5_digest *d1, const struct md5_digest *d2);
156++const char *sha256sum(uint8_t *buf, int len, int n_print_chars, struct gc_arena *gc);
157++void sha256_state_init (struct sha256_state *s);
158++void sha256_state_update (struct sha256_state *s, void *data, size_t len);
159++void sha256_state_final (struct sha256_state *s, struct sha256_digest *out);
160++void sha256_digest_clear (struct sha256_digest *digest);
161++bool sha256_digest_defined (const struct sha256_digest *digest);
162++bool sha256_digest_equal (const struct sha256_digest *d1, const struct sha256_digest *d2);
163+
164+ /*
165+ * Inline functions
166+diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
167+index 4c1ce9f..bd2a387 100644
168+--- a/src/openvpn/crypto_backend.h
169++++ b/src/openvpn/crypto_backend.h
170+@@ -480,10 +480,11 @@ void md_ctx_final (md_ctx_t *ctx, uint8_t *dst);
171+ * @param key The key to use for the HMAC
172+ * @param key_len The key length to use
173+ * @param kt Static message digest parameters
174++ * @param prf_use Intended use for PRF in TLS protocol
175+ *
176+ */
177+ void hmac_ctx_init (hmac_ctx_t *ctx, const uint8_t *key, int key_length,
178+- const md_kt_t *kt);
179++ const md_kt_t *kt, bool prf_use);
180+
181+ /*
182+ * Free the given HMAC context.
183+diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
184+index 229401d..ba59e04 100644
185+--- a/src/openvpn/crypto_openssl.c
186++++ b/src/openvpn/crypto_openssl.c
187+@@ -812,13 +812,17 @@ md_ctx_final (EVP_MD_CTX *ctx, uint8_t *dst)
188+
189+ void
190+ hmac_ctx_init (HMAC_CTX *ctx, const uint8_t *key, int key_len,
191+- const EVP_MD *kt)
192++ const EVP_MD *kt, bool prf_use)
193+ {
194+ ASSERT(NULL != kt && NULL != ctx);
195+
196+ CLEAR(*ctx);
197+
198+ HMAC_CTX_init (ctx);
199++ /* FIPS 140-2 explicitly allows MD5 for the use in PRF although it is not
200++ * to be used anywhere else */
201++ if(kt == EVP_md5() && prf_use)
202++ HMAC_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
203+ HMAC_Init_ex (ctx, key, key_len, kt, NULL);
204+
205+ /* make sure we used a big enough key */
206+diff --git a/src/openvpn/crypto_openssl.h b/src/openvpn/crypto_openssl.h
207+index f883c2a..37b9d75 100644
208+--- a/src/openvpn/crypto_openssl.h
209++++ b/src/openvpn/crypto_openssl.h
210+@@ -33,6 +33,7 @@
211+ #include <openssl/evp.h>
212+ #include <openssl/hmac.h>
213+ #include <openssl/md5.h>
214++#include <openssl/sha.h>
215+
216+ /** Generic cipher key type %context. */
217+ typedef EVP_CIPHER cipher_kt_t;
218+diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c
219+index 67f3c5f..0f7d8f9 100644
220+--- a/src/openvpn/crypto_polarssl.c
221++++ b/src/openvpn/crypto_polarssl.c
222+@@ -665,7 +665,7 @@ md_ctx_final (md_context_t *ctx, uint8_t *dst)
223+ * TODO: re-enable dmsg for crypto debug
224+ */
225+ void
226+-hmac_ctx_init (md_context_t *ctx, const uint8_t *key, int key_len, const md_info_t *kt)
227++hmac_ctx_init (md_context_t *ctx, const uint8_t *key, int key_len, const md_info_t *kt, bool prf_use)
228+ {
229+ ASSERT(NULL != kt && NULL != ctx);
230+
231+diff --git a/src/openvpn/init.c b/src/openvpn/init.c
232+index 2148777..7a9b266 100644
233+--- a/src/openvpn/init.c
234++++ b/src/openvpn/init.c
235+@@ -1360,12 +1360,12 @@ do_route (const struct options *options,
236+ */
237+ #if P2MP
238+ static void
239+-save_pulled_options_digest (struct context *c, const struct md5_digest *newdigest)
240++save_pulled_options_digest (struct context *c, const struct sha256_digest *newdigest)
241+ {
242+ if (newdigest)
243+ c->c1.pulled_options_digest_save = *newdigest;
244+ else
245+- md5_digest_clear (&c->c1.pulled_options_digest_save);
246++ sha256_digest_clear (&c->c1.pulled_options_digest_save);
247+ }
248+ #endif
249+
250+@@ -1695,8 +1695,8 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
251+ if (!c->c2.did_open_tun
252+ && PULL_DEFINED (&c->options)
253+ && c->c1.tuntap
254+- && (!md5_digest_defined (&c->c1.pulled_options_digest_save) || !md5_digest_defined (&c->c2.pulled_options_digest)
255+- || !md5_digest_equal (&c->c1.pulled_options_digest_save, &c->c2.pulled_options_digest)))
256++ && (!sha256_digest_defined (&c->c1.pulled_options_digest_save) || !sha256_digest_defined (&c->c2.pulled_options_digest)
257++ || !sha256_digest_equal (&c->c1.pulled_options_digest_save, &c->c2.pulled_options_digest)))
258+ {
259+ /* if so, close tun, delete routes, then reinitialize tun and add routes */
260+ msg (M_INFO, "NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device.");
261+@@ -2774,11 +2774,11 @@ do_compute_occ_strings (struct context *c)
262+ #ifdef ENABLE_CRYPTO
263+ msg (D_SHOW_OCC_HASH, "Local Options hash (VER=%s): '%s'",
264+ options_string_version (c->c2.options_string_local, &gc),
265+- md5sum ((uint8_t*)c->c2.options_string_local,
266++ sha256sum ((uint8_t*)c->c2.options_string_local,
267+ strlen (c->c2.options_string_local), 9, &gc));
268+ msg (D_SHOW_OCC_HASH, "Expected Remote Options hash (VER=%s): '%s'",
269+ options_string_version (c->c2.options_string_remote, &gc),
270+- md5sum ((uint8_t*)c->c2.options_string_remote,
271++ sha256sum ((uint8_t*)c->c2.options_string_remote,
272+ strlen (c->c2.options_string_remote), 9, &gc));
273+ #endif
274+
275+diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c
276+index 13bbc16..87b4037 100644
277+--- a/src/openvpn/ntlm.c
278++++ b/src/openvpn/ntlm.c
279+@@ -90,7 +90,7 @@ gen_hmac_md5 (const char* data, int data_len, const char* key, int key_len,char
280+ hmac_ctx_t hmac_ctx;
281+ CLEAR(hmac_ctx);
282+
283+- hmac_ctx_init(&hmac_ctx, key, key_len, md5_kt);
284++ hmac_ctx_init(&hmac_ctx, key, key_len, md5_kt, 0);
285+ hmac_ctx_update(&hmac_ctx, (const unsigned char *)data, data_len);
286+ hmac_ctx_final(&hmac_ctx, (unsigned char *)result);
287+ hmac_ctx_cleanup(&hmac_ctx);
288+diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h
289+index 36c3100..6400a05 100644
290+--- a/src/openvpn/openvpn.h
291++++ b/src/openvpn/openvpn.h
292+@@ -205,7 +205,7 @@ struct context_1
293+ #endif
294+
295+ /* if client mode, hash of option strings we pulled from server */
296+- struct md5_digest pulled_options_digest_save;
297++ struct sha256_digest pulled_options_digest_save;
298+ /**< Hash of option strings received from the
299+ * remote OpenVPN server. Only used in
300+ * client-mode. */
301+@@ -473,9 +473,9 @@ struct context_2
302+ bool did_pre_pull_restore;
303+
304+ /* hash of pulled options, so we can compare when options change */
305+- bool pulled_options_md5_init_done;
306+- struct md5_state pulled_options_state;
307+- struct md5_digest pulled_options_digest;
308++ bool pulled_options_sha256_init_done;
309++ struct sha256_state pulled_options_state;
310++ struct sha256_digest pulled_options_digest;
311+
312+ struct event_timeout server_poll_interval;
313+
314+diff --git a/src/openvpn/push.c b/src/openvpn/push.c
315+index e4f3984..b903586 100644
316+--- a/src/openvpn/push.c
317++++ b/src/openvpn/push.c
318+@@ -455,10 +455,10 @@ process_incoming_push_msg (struct context *c,
319+ if (ch == ',')
320+ {
321+ struct buffer buf_orig = buf;
322+- if (!c->c2.pulled_options_md5_init_done)
323++ if (!c->c2.pulled_options_sha256_init_done)
324+ {
325+- md5_state_init (&c->c2.pulled_options_state);
326+- c->c2.pulled_options_md5_init_done = true;
327++ sha256_state_init (&c->c2.pulled_options_state);
328++ c->c2.pulled_options_sha256_init_done = true;
329+ }
330+ if (!c->c2.did_pre_pull_restore)
331+ {
332+@@ -474,13 +474,13 @@ process_incoming_push_msg (struct context *c,
333+ {
334+ case 0:
335+ case 1:
336+- md5_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig));
337+- md5_state_final (&c->c2.pulled_options_state, &c->c2.pulled_options_digest);
338+- c->c2.pulled_options_md5_init_done = false;
339++ sha256_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig));
340++ sha256_state_final (&c->c2.pulled_options_state, &c->c2.pulled_options_digest);
341++ c->c2.pulled_options_sha256_init_done = false;
342+ ret = PUSH_MSG_REPLY;
343+ break;
344+ case 2:
345+- md5_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig));
346++ sha256_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig));
347+ ret = PUSH_MSG_CONTINUATION;
348+ break;
349+ }
350+diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
351+index 0679890..47fc702 100644
352+--- a/src/openvpn/ssl.c
353++++ b/src/openvpn/ssl.c
354+@@ -1375,8 +1375,8 @@ tls1_P_hash(const md_kt_t *md_kt,
355+ chunk = md_kt_size(md_kt);
356+ A1_len = md_kt_size(md_kt);
357+
358+- hmac_ctx_init(&ctx, sec, sec_len, md_kt);
359+- hmac_ctx_init(&ctx_tmp, sec, sec_len, md_kt);
360++ hmac_ctx_init(&ctx, sec, sec_len, md_kt, 1);
361++ hmac_ctx_init(&ctx_tmp, sec, sec_len, md_kt, 1);
362+
363+ hmac_ctx_update(&ctx,seed,seed_len);
364+ hmac_ctx_final(&ctx, A1);
365diff --git a/debian/patches/series b/debian/patches/series
366index 9ccb035..b538685 100644
367--- a/debian/patches/series
368+++ b/debian/patches/series
369@@ -14,3 +14,4 @@ CVE-2017-7512.patch
370 CVE-2017-7520.patch
371 CVE-2017-7521.patch
372 establish_http_proxy_passthru_dos.patch
373+openvpn-fips140-2.3.2.patch

Subscribers

People subscribed via source and target branches