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

Subscribers

People subscribed via source and target branches